blob: c560b3e58ac4ea8d353af67fb5a58d9027822699 [file] [log] [blame]
Brad Bishop19323692019-04-05 15:28:33 -04001#! /usr/bin/env python3
2#
3# Copyright (C) 2018 Garmin Ltd.
4#
Brad Bishopc342db32019-05-15 21:57:59 -04005# SPDX-License-Identifier: GPL-2.0-only
Brad Bishop19323692019-04-05 15:28:33 -04006#
Brad Bishopc342db32019-05-15 21:57:59 -04007
Brad Bishop19323692019-04-05 15:28:33 -04008import os
9import sys
10import logging
11import argparse
12import sqlite3
Andrew Geissler5199d832021-09-24 16:47:35 -050013import warnings
Patrick Williamsac13d5f2023-11-24 18:59:46 -060014
Andrew Geissler5199d832021-09-24 16:47:35 -050015warnings.simplefilter("default")
Brad Bishop19323692019-04-05 15:28:33 -040016
Patrick Williamsac13d5f2023-11-24 18:59:46 -060017sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), "lib"))
Brad Bishop19323692019-04-05 15:28:33 -040018
19import hashserv
Patrick Williamsac13d5f2023-11-24 18:59:46 -060020from hashserv.server import DEFAULT_ANON_PERMS
Brad Bishop19323692019-04-05 15:28:33 -040021
22VERSION = "1.0.0"
23
Patrick Williamsac13d5f2023-11-24 18:59:46 -060024DEFAULT_BIND = "unix://./hashserve.sock"
Brad Bishopa34c0302019-09-23 22:34:48 -040025
Brad Bishop19323692019-04-05 15:28:33 -040026
27def main():
Patrick Williamsac13d5f2023-11-24 18:59:46 -060028 parser = argparse.ArgumentParser(
29 description="Hash Equivalence Reference Server. Version=%s" % VERSION,
30 formatter_class=argparse.RawTextHelpFormatter,
31 epilog="""
32The bind address may take one of the following formats:
33 unix://PATH - Bind to unix domain socket at PATH
34 ws://ADDRESS:PORT - Bind to websocket on ADDRESS:PORT
35 ADDRESS:PORT - Bind to raw TCP socket on ADDRESS:PORT
Brad Bishopa34c0302019-09-23 22:34:48 -040036
Patrick Williamsac13d5f2023-11-24 18:59:46 -060037To bind to all addresses, leave the ADDRESS empty, e.g. "--bind :8686" or
38"--bind ws://:8686". To bind to a specific IPv6 address, enclose the address in
39"[]", e.g. "--bind [::1]:8686" or "--bind ws://[::1]:8686"
40
41Note that the default Anonymous permissions are designed to not break existing
42server instances when upgrading, but are not particularly secure defaults. If
43you want to use authentication, it is recommended that you use "--anon-perms
44@read" to only give anonymous users read access, or "--anon-perms @none" to
45give un-authenticated users no access at all.
46
47Setting "--anon-perms @all" or "--anon-perms @user-admin" is not allowed, since
48this would allow anonymous users to manage all users accounts, which is a bad
49idea.
50
51If you are using user authentication, you should run your server in websockets
52mode with an SSL terminating load balancer in front of it (as this server does
53not implement SSL). Otherwise all usernames and passwords will be transmitted
54in the clear. When configured this way, clients can connect using a secure
55websocket, as in "wss://SERVER:PORT"
56 """,
57 )
58
59 parser.add_argument(
60 "-b",
61 "--bind",
62 default=os.environ.get("HASHSERVER_BIND", DEFAULT_BIND),
63 help='Bind address (default $HASHSERVER_BIND, "%(default)s")',
64 )
65 parser.add_argument(
66 "-d",
67 "--database",
68 default=os.environ.get("HASHSERVER_DB", "./hashserv.db"),
69 help='Database file (default $HASHSERVER_DB, "%(default)s")',
70 )
71 parser.add_argument(
72 "-l",
73 "--log",
74 default=os.environ.get("HASHSERVER_LOG_LEVEL", "WARNING"),
75 help='Set logging level (default $HASHSERVER_LOG_LEVEL, "%(default)s")',
76 )
77 parser.add_argument(
78 "-u",
79 "--upstream",
80 default=os.environ.get("HASHSERVER_UPSTREAM", None),
81 help="Upstream hashserv to pull hashes from ($HASHSERVER_UPSTREAM)",
82 )
83 parser.add_argument(
84 "-r",
85 "--read-only",
86 action="store_true",
87 help="Disallow write operations from clients ($HASHSERVER_READ_ONLY)",
88 )
89 parser.add_argument(
90 "--db-username",
91 default=os.environ.get("HASHSERVER_DB_USERNAME", None),
92 help="Database username ($HASHSERVER_DB_USERNAME)",
93 )
94 parser.add_argument(
95 "--db-password",
96 default=os.environ.get("HASHSERVER_DB_PASSWORD", None),
97 help="Database password ($HASHSERVER_DB_PASSWORD)",
98 )
99 parser.add_argument(
100 "--anon-perms",
101 metavar="PERM[,PERM[,...]]",
102 default=os.environ.get("HASHSERVER_ANON_PERMS", ",".join(DEFAULT_ANON_PERMS)),
103 help='Permissions to give anonymous users (default $HASHSERVER_ANON_PERMS, "%(default)s")',
104 )
105 parser.add_argument(
106 "--admin-user",
107 default=os.environ.get("HASHSERVER_ADMIN_USER", None),
108 help="Create default admin user with name ADMIN_USER ($HASHSERVER_ADMIN_USER)",
109 )
110 parser.add_argument(
111 "--admin-password",
112 default=os.environ.get("HASHSERVER_ADMIN_PASSWORD", None),
113 help="Create default admin user with password ADMIN_PASSWORD ($HASHSERVER_ADMIN_PASSWORD)",
114 )
Brad Bishop19323692019-04-05 15:28:33 -0400115
116 args = parser.parse_args()
117
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600118 logger = logging.getLogger("hashserv")
Brad Bishop19323692019-04-05 15:28:33 -0400119
120 level = getattr(logging, args.log.upper(), None)
121 if not isinstance(level, int):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600122 raise ValueError("Invalid log level: %s" % args.log)
Brad Bishop19323692019-04-05 15:28:33 -0400123
124 logger.setLevel(level)
125 console = logging.StreamHandler()
126 console.setLevel(level)
127 logger.addHandler(console)
128
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600129 read_only = (os.environ.get("HASHSERVER_READ_ONLY", "0") == "1") or args.read_only
130 if "," in args.anon_perms:
131 anon_perms = args.anon_perms.split(",")
132 else:
133 anon_perms = args.anon_perms.split()
134
135 server = hashserv.create_server(
136 args.bind,
137 args.database,
138 upstream=args.upstream,
139 read_only=read_only,
140 db_username=args.db_username,
141 db_password=args.db_password,
142 anon_perms=anon_perms,
143 admin_username=args.admin_user,
144 admin_password=args.admin_password,
145 )
Brad Bishop19323692019-04-05 15:28:33 -0400146 server.serve_forever()
147 return 0
148
Brad Bishopa34c0302019-09-23 22:34:48 -0400149
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600150if __name__ == "__main__":
Brad Bishop19323692019-04-05 15:28:33 -0400151 try:
152 ret = main()
153 except Exception:
154 ret = 1
155 import traceback
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600156
Brad Bishop19323692019-04-05 15:28:33 -0400157 traceback.print_exc()
158 sys.exit(ret)