| #! /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)", |
| ) |
| |
| 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, |
| ) |
| server.serve_forever() |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| try: |
| ret = main() |
| except Exception: |
| ret = 1 |
| import traceback |
| |
| traceback.print_exc() |
| sys.exit(ret) |