diff options
author | clarkzjw <[email protected]> | 2023-02-23 15:38:38 -0800 |
---|---|---|
committer | clarkzjw <[email protected]> | 2023-02-23 15:38:38 -0800 |
commit | 20b8220a12fc92f95ecae267ce4eb5a80584f564 (patch) | |
tree | 1090256b48a76aae7afe2e10b860a02b43790807 | |
parent | 31a2d111d1c0ceb2ebfd5bb5daf4ee0ab2de4eb4 (diff) | |
parent | 4cee8500a51aff6d0a445a3a6259cafed92d4845 (diff) | |
download | swarm2fediverse-20b8220a12fc92f95ecae267ce4eb5a80584f564.tar.gz |
Merge branch 'feature/encryption'
- bot: encrypt access_key with cryptography.fernet library
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | bot.py | 5 | ||||
-rw-r--r-- | callback.py | 22 | ||||
-rw-r--r-- | config.ini.example | 1 | ||||
-rw-r--r-- | config.py | 2 | ||||
-rw-r--r-- | dbstore/peewee_store.py | 6 | ||||
-rw-r--r-- | util.py | 18 |
7 files changed, 36 insertions, 19 deletions
@@ -24,4 +24,3 @@ Foursquare Swarm like Telegram bot to check in at places and post to Fediverse ( | |||
24 | - [ ] add Telegram payment option to enable raw GPS checkins | 24 | - [ ] add Telegram payment option to enable raw GPS checkins |
25 | - [ ] i18n | 25 | - [ ] i18n |
26 | - [ ] Anonymized usage analysis, monitoring (Grafana/Prometheus) | 26 | - [ ] Anonymized usage analysis, monitoring (Grafana/Prometheus) |
27 | |||
@@ -4,7 +4,7 @@ import asyncio | |||
4 | import logging | 4 | import logging |
5 | from dataclasses import dataclass | 5 | from dataclasses import dataclass |
6 | from http import HTTPStatus | 6 | from http import HTTPStatus |
7 | from config import BOT_TOKEN, TELEGRAM_WEBHOOK_URL, HEALTHCHECK_URL, FEDI_LOGIN_CALLBACK_URL, BOT_DOMAIN, BOT_PORT | 7 | from config import BOT_TOKEN, TELEGRAM_WEBHOOK_URL, HEALTHCHECK_URL, FEDI_LOGIN_CALLBACK_URL, BOT_DOMAIN, BOT_PORT, ENCRYPT_KEY |
8 | import uvicorn | 8 | import uvicorn |
9 | from starlette.applications import Starlette | 9 | from starlette.applications import Starlette |
10 | from starlette.requests import Request | 10 | from starlette.requests import Request |
@@ -61,6 +61,7 @@ from config import ( | |||
61 | from prompt.string import PROMPT_CHOOSE_ACTION | 61 | from prompt.string import PROMPT_CHOOSE_ACTION |
62 | from mastodon import Mastodon | 62 | from mastodon import Mastodon |
63 | from dbstore.peewee_store import db, User, get_user_by_state | 63 | from dbstore.peewee_store import db, User, get_user_by_state |
64 | from util import encrypt, decrypt | ||
64 | 65 | ||
65 | logging.basicConfig( | 66 | logging.basicConfig( |
66 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO | 67 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO |
@@ -104,7 +105,7 @@ async def process_oauth_login_callback(update: FediLoginCallbackUpdate, context: | |||
104 | redirect_uri="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | 105 | redirect_uri="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), |
105 | scopes=BOT_SCOPE | 106 | scopes=BOT_SCOPE |
106 | ) | 107 | ) |
107 | user.access_key = access_token | 108 | user.access_key = encrypt(access_token, ENCRYPT_KEY) |
108 | user.save() | 109 | user.save() |
109 | 110 | ||
110 | text = "You have successfully logged in to your Mastodon account!" | 111 | text = "You have successfully logged in to your Mastodon account!" |
diff --git a/callback.py b/callback.py index d968523..a1b4b2d 100644 --- a/callback.py +++ b/callback.py | |||
@@ -9,10 +9,11 @@ from command import * | |||
9 | from dbstore.peewee_store import get_poi_by_fsq_id | 9 | from dbstore.peewee_store import get_poi_by_fsq_id |
10 | from foursquare.poi import OSM_ENDPOINT | 10 | from foursquare.poi import OSM_ENDPOINT |
11 | from foursquare.poi import query_poi | 11 | from foursquare.poi import query_poi |
12 | from config import BOT_SCOPE | 12 | from config import BOT_SCOPE, ENCRYPT_KEY |
13 | from dbstore.peewee_store import User, db, TOOT_VISIBILITY_PRIVATE, TOOT_VISIBILITY_PUBLIC, TOOT_VISIBILITY_UNLISTED | 13 | from dbstore.peewee_store import User, db, TOOT_VISIBILITY_PRIVATE, TOOT_VISIBILITY_PUBLIC, TOOT_VISIBILITY_UNLISTED |
14 | import uuid | 14 | import uuid |
15 | from mastodon import Mastodon | 15 | from mastodon import Mastodon |
16 | from util import decrypt | ||
16 | 17 | ||
17 | 18 | ||
18 | def generate_uuid(): | 19 | def generate_uuid(): |
@@ -23,7 +24,7 @@ def get_mastodon_client(user_id: int): | |||
23 | with db.connection_context(): | 24 | with db.connection_context(): |
24 | user = User.get(User.telegram_user_id == user_id) | 25 | user = User.get(User.telegram_user_id == user_id) |
25 | if user.home_instance and user.access_key: | 26 | if user.home_instance and user.access_key: |
26 | return Mastodon(access_token=user.access_key, api_base_url=user.home_instance) | 27 | return Mastodon(access_token=decrypt(user.access_key, ENCRYPT_KEY), api_base_url=user.home_instance) |
27 | 28 | ||
28 | 29 | ||
29 | def generate_toot_text(poi_name, poi_locality, poi_region, poi_lat, poi_lon): | 30 | def generate_toot_text(poi_name, poi_locality, poi_region, poi_lat, poi_lon): |
@@ -85,21 +86,20 @@ async def callback_generate_fedi_login_url(update: Update, context: ContextTypes | |||
85 | user_id = update.effective_user.id | 86 | user_id = update.effective_user.id |
86 | state = generate_uuid() | 87 | state = generate_uuid() |
87 | 88 | ||
88 | db.connect() | 89 | with db.connection_context(): |
89 | u = User.get_or_none(telegram_user_id=user_id) | 90 | u = User.get_or_none(telegram_user_id=user_id) |
90 | if u is None: | 91 | if u is None: |
91 | u = User.create(telegram_user_id=user_id, access_key="", home_instance=home_instance, | 92 | u = User.create(telegram_user_id=user_id, access_key="", home_instance=home_instance, |
92 | client_id=client_id, client_secret=client_secret, state=state) | 93 | client_id=client_id, client_secret=client_secret, state=state) |
93 | u.save() | 94 | u.save() |
94 | db.close() | ||
95 | 95 | ||
96 | oauth_url = m.auth_request_url(redirect_uris="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | 96 | oauth_url = m.auth_request_url(redirect_uris="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), |
97 | scopes=BOT_SCOPE, | 97 | scopes=BOT_SCOPE, |
98 | state=state) | 98 | state=state) |
99 | 99 | ||
100 | msg = await update.message.reply_text(PROMPT_FEDI_LOGIN, | 100 | msg = await update.message.reply_text(PROMPT_FEDI_LOGIN, |
101 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Login", url=oauth_url)]]), | 101 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Login", url=oauth_url)]]), |
102 | parse_mode=ParseMode.MARKDOWN) | 102 | parse_mode=ParseMode.MARKDOWN) |
103 | 103 | ||
104 | context.user_data[PROMPT_FEDI_LOGIN] = msg.message_id | 104 | context.user_data[PROMPT_FEDI_LOGIN] = msg.message_id |
105 | return FEDI_LOGIN | 105 | return FEDI_LOGIN |
diff --git a/config.ini.example b/config.ini.example index 2efd6d5..e3a9121 100644 --- a/config.ini.example +++ b/config.ini.example | |||
@@ -1,3 +1,4 @@ | |||
1 | [DEFAULT] | 1 | [DEFAULT] |
2 | BOT_TOKEN = | 2 | BOT_TOKEN = |
3 | FOURSQUARE_API_KEY = | 3 | FOURSQUARE_API_KEY = |
4 | ENCRYPT_KEY = | ||
@@ -8,7 +8,7 @@ config.read("config.ini") | |||
8 | 8 | ||
9 | BOT_TOKEN = config["DEFAULT"]["BOT_TOKEN"] | 9 | BOT_TOKEN = config["DEFAULT"]["BOT_TOKEN"] |
10 | FSQ_API_KEY = config["DEFAULT"]["FOURSQUARE_API_KEY"] | 10 | FSQ_API_KEY = config["DEFAULT"]["FOURSQUARE_API_KEY"] |
11 | 11 | ENCRYPT_KEY = config["DEFAULT"]["ENCRYPT_KEY"] | |
12 | 12 | ||
13 | MEDIA_GROUP_TIMEOUT = 3 | 13 | MEDIA_GROUP_TIMEOUT = 3 |
14 | 14 | ||
diff --git a/dbstore/peewee_store.py b/dbstore/peewee_store.py index d124de2..445816e 100644 --- a/dbstore/peewee_store.py +++ b/dbstore/peewee_store.py | |||
@@ -16,10 +16,8 @@ class BaseModel(Model): | |||
16 | 16 | ||
17 | class User(BaseModel): | 17 | class User(BaseModel): |
18 | telegram_user_id = CharField(unique=True, primary_key=True) | 18 | telegram_user_id = CharField(unique=True, primary_key=True) |
19 | # TODO: | 19 | access_key = CharField(max_length=256) |
20 | # add AES encryption to access_key | 20 | home_instance = CharField(max_length=256) |
21 | access_key = CharField(max_length=64) | ||
22 | home_instance = CharField(max_length=128) | ||
23 | state = CharField(max_length=128) | 21 | state = CharField(max_length=128) |
24 | client_id = CharField(max_length=128) | 22 | client_id = CharField(max_length=128) |
25 | client_secret = CharField(max_length=128) | 23 | client_secret = CharField(max_length=128) |
@@ -0,0 +1,18 @@ | |||
1 | from cryptography.fernet import Fernet | ||
2 | |||
3 | |||
4 | def encrypt(input: str, key: str) -> str: | ||
5 | f = Fernet(key) | ||
6 | return f.encrypt(bytes(input, 'utf-8')).decode('utf-8') | ||
7 | |||
8 | |||
9 | def decrypt(input: str, key: str) -> str: | ||
10 | f = Fernet(key) | ||
11 | return f.decrypt(input).decode('utf-8') | ||
12 | |||
13 | |||
14 | # if __name__ == "__main__": | ||
15 | # key = Fernet.generate_key().decode('utf-8') | ||
16 | # print(key) | ||
17 | # print(encrypt("Hello World!", key)) | ||
18 | # print(decrypt(encrypt("Hello World!", key), key)) | ||