123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- #! /usr/bin/env python3
- #
- # Copyright (C) 2018 Garmin Ltd.
- #
- # SPDX-License-Identifier: GPL-2.0-only
- #
- import os
- import sys
- import logging
- import argparse
- import sqlite3
- import warnings
- warnings.simplefilter("default")
- sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), "lib"))
- import hashserv
- from hashserv.server import DEFAULT_ANON_PERMS
- VERSION = "1.0.0"
- DEFAULT_BIND = "unix://./hashserve.sock"
- def main():
- parser = argparse.ArgumentParser(
- description="Hash Equivalence Reference Server. Version=%s" % VERSION,
- formatter_class=argparse.RawTextHelpFormatter,
- epilog="""
- The bind address may take one of the following formats:
- unix://PATH - Bind to unix domain socket at PATH
- ws://ADDRESS:PORT - Bind to websocket on ADDRESS:PORT
- ADDRESS:PORT - Bind to raw TCP socket on ADDRESS:PORT
- To bind to all addresses, leave the ADDRESS empty, e.g. "--bind :8686" or
- "--bind ws://:8686". To bind to a specific IPv6 address, enclose the address in
- "[]", e.g. "--bind [::1]:8686" or "--bind ws://[::1]:8686"
- Note that the default Anonymous permissions are designed to not break existing
- server instances when upgrading, but are not particularly secure defaults. If
- you want to use authentication, it is recommended that you use "--anon-perms
- @read" to only give anonymous users read access, or "--anon-perms @none" to
- give un-authenticated users no access at all.
- Setting "--anon-perms @all" or "--anon-perms @user-admin" is not allowed, since
- this would allow anonymous users to manage all users accounts, which is a bad
- idea.
- If you are using user authentication, you should run your server in websockets
- mode with an SSL terminating load balancer in front of it (as this server does
- not implement SSL). Otherwise all usernames and passwords will be transmitted
- in the clear. When configured this way, clients can connect using a secure
- websocket, as in "wss://SERVER:PORT"
- The following permissions are supported by the server:
- @none - No permissions
- @read - The ability to read equivalent hashes from the server
- @report - The ability to report equivalent hashes to the server
- @db-admin - Manage the hash database(s). This includes cleaning the
- database, removing hashes, etc.
- @user-admin - The ability to manage user accounts. This includes, creating
- users, deleting users, resetting login tokens, and assigning
- permissions.
- @all - All possible permissions, including any that may be added
- in the future
- """,
- )
- parser.add_argument(
- "-b",
- "--bind",
- default=os.environ.get("HASHSERVER_BIND", DEFAULT_BIND),
- help='Bind address (default $HASHSERVER_BIND, "%(default)s")',
- )
- parser.add_argument(
- "-d",
- "--database",
- default=os.environ.get("HASHSERVER_DB", "./hashserv.db"),
- help='Database file (default $HASHSERVER_DB, "%(default)s")',
- )
- parser.add_argument(
- "-l",
- "--log",
- default=os.environ.get("HASHSERVER_LOG_LEVEL", "WARNING"),
- help='Set logging level (default $HASHSERVER_LOG_LEVEL, "%(default)s")',
- )
- parser.add_argument(
- "-u",
- "--upstream",
- default=os.environ.get("HASHSERVER_UPSTREAM", None),
- help="Upstream hashserv to pull hashes from ($HASHSERVER_UPSTREAM)",
- )
- parser.add_argument(
- "-r",
- "--read-only",
- action="store_true",
- help="Disallow write operations from clients ($HASHSERVER_READ_ONLY)",
- )
- parser.add_argument(
- "--db-username",
- default=os.environ.get("HASHSERVER_DB_USERNAME", None),
- help="Database username ($HASHSERVER_DB_USERNAME)",
- )
- parser.add_argument(
- "--db-password",
- default=os.environ.get("HASHSERVER_DB_PASSWORD", None),
- help="Database password ($HASHSERVER_DB_PASSWORD)",
- )
- parser.add_argument(
- "--anon-perms",
- metavar="PERM[,PERM[,...]]",
- default=os.environ.get("HASHSERVER_ANON_PERMS", ",".join(DEFAULT_ANON_PERMS)),
- help='Permissions to give anonymous users (default $HASHSERVER_ANON_PERMS, "%(default)s")',
- )
- parser.add_argument(
- "--admin-user",
- default=os.environ.get("HASHSERVER_ADMIN_USER", None),
- help="Create default admin user with name ADMIN_USER ($HASHSERVER_ADMIN_USER)",
- )
- parser.add_argument(
- "--admin-password",
- default=os.environ.get("HASHSERVER_ADMIN_PASSWORD", None),
- help="Create default admin user with password ADMIN_PASSWORD ($HASHSERVER_ADMIN_PASSWORD)",
- )
- parser.add_argument(
- "--reuseport",
- action="store_true",
- help="Enable SO_REUSEPORT, allowing multiple servers to bind to the same port for load balancing",
- )
- args = parser.parse_args()
- logger = logging.getLogger("hashserv")
- level = getattr(logging, args.log.upper(), None)
- if not isinstance(level, int):
- raise ValueError(
- "Invalid log level: %s (Try ERROR/WARNING/INFO/DEBUG)" % args.log
- )
- logger.setLevel(level)
- console = logging.StreamHandler()
- console.setLevel(level)
- logger.addHandler(console)
- read_only = (os.environ.get("HASHSERVER_READ_ONLY", "0") == "1") or args.read_only
- if "," in args.anon_perms:
- anon_perms = args.anon_perms.split(",")
- else:
- anon_perms = args.anon_perms.split()
- server = hashserv.create_server(
- args.bind,
- args.database,
- upstream=args.upstream,
- read_only=read_only,
- db_username=args.db_username,
- db_password=args.db_password,
- anon_perms=anon_perms,
- admin_username=args.admin_user,
- admin_password=args.admin_password,
- reuseport=args.reuseport,
- )
- server.serve_forever()
- return 0
- if __name__ == "__main__":
- try:
- ret = main()
- except Exception:
- ret = 1
- import traceback
- traceback.print_exc()
- sys.exit(ret)
|