From 0c22c415b1f25e2da578c7f322a8561c05b5e4a5 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Wed, 18 Mar 2020 16:41:32 +1000 Subject: [PATCH] provide webfinger and actor info with rsa key for secure fetch --- app/functions.py | 27 +++++++++++++++++++++++++++ app/templates/ap/actor.json | 24 ++++++++++++++++++++++++ app/templates/ap/webfinger.json | 13 +++++++++++++ app/webui.py | 17 +++++++++++++---- db/setup.sql | 20 ++++++++++++-------- requirements.txt | 1 + 6 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 app/templates/ap/actor.json create mode 100644 app/templates/ap/webfinger.json diff --git a/app/functions.py b/app/functions.py index 5d0d743..e03e1f8 100644 --- a/app/functions.py +++ b/app/functions.py @@ -1,6 +1,7 @@ from bs4 import BeautifulSoup import MySQLdb import markovify +from Crypto.PublicKey import RSA from mastodon import Mastodon, MastodonUnauthorizedError import html, re, json @@ -175,3 +176,29 @@ def make_post(args): c.execute("UPDATE bots SET last_post = CURRENT_TIMESTAMP() WHERE handle = %s", (handle,)) db.commit() c.close() + +def get_key(): + db = MySQLdb.connect( + host = cfg['db_host'], + user=cfg['db_user'], + passwd=cfg['db_pass'], + db=cfg['db_name'] + ) + + dc = db.cursor(MySQLdb.cursors.DictCursor) + dc.execute("SELECT * FROM http_auth_key") + key = dc.fetchone() + if key == None: + # generate new key + key = {} + privkey = RSA.generate(4096) + + key['private'] = privkey.exportKey('PEM').decode('utf-8') + key['public'] = privkey.publickey().exportKey('PEM').decode('utf-8') + + dc.execute("INSERT INTO http_auth_key (private, public) VALUES (%s, %s)", (key['private'], key['public'])) + + dc.close() + db.commit() + + return key \ No newline at end of file diff --git a/app/templates/ap/actor.json b/app/templates/ap/actor.json new file mode 100644 index 0000000..393c73e --- /dev/null +++ b/app/templates/ap/actor.json @@ -0,0 +1,24 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers" + } + ], + "endpoints": { + "sharedInbox": "{{ base_uri }}/inbox" + }, + "inbox": "{{ base_uri }}/inbox", + "name": "FediBooks", + "type": "Application", + "id": "{{ base_uri }}/actor", + "manuallyApprovesFollowers": true, + "publicKey": { + "id": "{{ base_uri }}/actor#main-key", + "owner": "{{ base_uri }}/actor", + "publicKeyPem": "{{ pubkey }}" + }, + "summary": "FediBooks Actor", + "preferredUsername": "fedibooks", + "url": "{{ base_uri }}/actor" +} \ No newline at end of file diff --git a/app/templates/ap/webfinger.json b/app/templates/ap/webfinger.json new file mode 100644 index 0000000..a6c115b --- /dev/null +++ b/app/templates/ap/webfinger.json @@ -0,0 +1,13 @@ +{ + "aliases": [ + "{{ base_uri }}/actor" + ], + "links": [ + { + "href": "{{ base_uri }}/actor", + "rel": "self", + "type": "application/activity+json" + } + ], + "subject": "acct:fedibooks@{{ base_uri }}" +} \ No newline at end of file diff --git a/app/webui.py b/app/webui.py index 76a8f1f..1e2c693 100644 --- a/app/webui.py +++ b/app/webui.py @@ -32,7 +32,11 @@ scopes_pleroma = ['read', 'write', 'push'] @app.before_request def login_check(): - if request.path not in ['/', '/about', '/welcome', '/login', '/signup', '/do/login', '/do/signup'] and not request.path.startswith("/push") and not request.path.startswith('/static'): + if request.path not in ['/', '/about', '/welcome', '/login', '/signup', '/do/login', '/do/signup'] \ + and not request.path.startswith("/push") \ + and not request.path.startswith('/static') \ + and not request.path.startswith('/actor') \ + and not request.path.startswith('/.well-known'): # page requires authentication if 'user_id' not in session: return redirect(url_for('render_home')) @@ -370,9 +374,14 @@ def img_bot_generic(): def favicon(): return send_file("static/favicon.ico") -# @app.route("/.well-known/webfinger") -# def webfinger(): -# return render_template("webfinger.json", base_uri = cfg['base_uri']), 200, {'Content-type':'application/json'} +@app.route("/.well-known/webfinger") +def webfinger(): + return render_template("ap/webfinger.json", base_uri = cfg['base_uri']), 200, {'Content-type':'application/json'} + +@app.route("/actor") +def actor(): + pubkey = functions.get_key()['public'].replace("\n", "\\n") + return render_template("ap/actor.json", base_uri = cfg['base_uri'], pubkey = pubkey), 200, {'Content-type':'application/json'} def bot_check(bot): diff --git a/db/setup.sql b/db/setup.sql index c42361a..d999fa7 100644 --- a/db/setup.sql +++ b/db/setup.sql @@ -8,13 +8,13 @@ CREATE TABLE IF NOT EXISTS `users` ( `submit` ENUM('always', 'once', 'never') DEFAULT 'once', `generation` ENUM('always', 'once', 'never') DEFAULT 'once', `reply` ENUM('always', 'once', 'never') DEFAULT 'once' -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `credentials` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `client_id` VARCHAR(128) NOT NULL, `client_secret` VARCHAR(128) NOT NULL, `secret` VARCHAR(128) NOT NULL -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `bots` ( `handle` VARCHAR(128) PRIMARY KEY, `user_id` INT NOT NULL, @@ -37,7 +37,7 @@ CREATE TABLE IF NOT EXISTS `bots` ( `icon_update_time` DATETIME DEFAULT '1000-01-01 00:00:00', FOREIGN KEY (`user_id`) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (`credentials_id`) REFERENCES credentials(id) ON DELETE CASCADE -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `fedi_accounts` ( `handle` VARCHAR(128) PRIMARY KEY, `outbox` VARCHAR(256), @@ -45,14 +45,14 @@ CREATE TABLE IF NOT EXISTS `fedi_accounts` ( `icon` VARCHAR(512), `icon_update_time` DATETIME DEFAULT 0, FOREIGN KEY (`credentials_id`) REFERENCES credentials(id) ON DELETE CASCADE -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `bot_learned_accounts` ( `bot_id` VARCHAR(128) NOT NULL, `fedi_id` VARCHAR(128) NOT NULL, `enabled` BOOLEAN DEFAULT 1, FOREIGN KEY (`bot_id`) REFERENCES bots(handle) ON DELETE CASCADE, FOREIGN KEY (`fedi_id`) REFERENCES fedi_accounts(handle) ON DELETE CASCADE -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `posts` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `fedi_id` VARCHAR(128), @@ -60,14 +60,14 @@ CREATE TABLE IF NOT EXISTS `posts` ( `content` TEXT NOT NULL, `cw` BOOLEAN NOT NULL, FOREIGN KEY (`fedi_id`) REFERENCES fedi_accounts(handle) ON DELETE CASCADE -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `word_blacklist` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `bot_id` VARCHAR(128) NOT NULL, `phrase` VARCHAR(128) NOT NULL, `whole_word` BOOLEAN NOT NULL, FOREIGN KEY (`bot_id`) REFERENCES bots(handle) ON DELETE CASCADE -) ENGINE=INNODB; +) ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `contact_history` ( `user_id` INT NOT NULL, `fetch` BOOLEAN DEFAULT 0, @@ -75,4 +75,8 @@ CREATE TABLE IF NOT EXISTS `contact_history` ( `generation` BOOLEAN DEFAULT 0, `reply` BOOLEAN DEFAULT 0, FOREIGN KEY (`user_id`) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=INNODB; +) ENGINE = INNODB; +CREATE TABLE IF NOT EXISTS `http_auth_key` ( + `private` TEXT NOT NULL, + `public` TEXT NOT NULL +) ENGINE = INNODB; \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 248fd71..bf56093 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ bcrypt == 3.1.7 requests==2.23.0 http-ece==1.1.0 cryptography==2.8 +pycryptodome==3.9.7 \ No newline at end of file