chore: Upload redacted and annotated legacy version of the service.
This commit is contained in:
1 parent
a2bf471162
commit
8a5d9e94ff
1 file changed
+343
@@ -0,0 +1,343 @@
|
||||
from flask import Flask
|
||||
from flask import make_response
|
||||
from flask import jsonify
|
||||
from flask import request
|
||||
from flask import g
|
||||
from flask import redirect
|
||||
|
||||
from markupsafe import escape
|
||||
|
||||
import json
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
import random
|
||||
|
||||
MEETUP_INVITE_CLIENT_VERSION='v3.0.0'
|
||||
DATABASE = '/.hmc-meetups/hmc-meetups.db'
|
||||
AGREEMENT_SUCCESS_URL = 'https://handmadecities.com/meetups-success'
|
||||
|
||||
# NOTE(jmug): This was a large list of invite codes, request the "invite-codes"
|
||||
# string array secret from secrets server, client at:
|
||||
# https://git.handmadecities.com/HMC/shhh/src/commit/36af43779460dcfd818d1481abeded14fa45e1a4/pkg/secretsclient/cli.go#L12-L34
|
||||
INVITE_CODES = ["<redacted>"]
|
||||
|
||||
# NOTE(jmug): This was a map of "cities" to a shared secret corresponding to each city, request the "city-secrets"
|
||||
# string map secret from secrets server, client at:
|
||||
# https://git.handmadecities.com/HMC/shhh/src/commit/36af43779460dcfd818d1481abeded14fa45e1a4/pkg/secretsclient/cli.go#L12-L34
|
||||
shared_secrets = {
|
||||
'<redacted>': '<redacted>',
|
||||
}
|
||||
|
||||
# Flask config
|
||||
|
||||
def home():
|
||||
if os.name == 'nt':
|
||||
return os.getenv('HOMEPATH')
|
||||
else:
|
||||
return os.getenv('HOME')
|
||||
|
||||
app = Flask(__name__)
|
||||
# NOTE(jmug): Flask uses this secret_key to validate cookies, among other things,
|
||||
# we hsould not have a need for this in a Go port.
|
||||
app.secret_key = '<redacted>'
|
||||
|
||||
start_time = datetime.datetime.now()
|
||||
logname = start_time.strftime('flask-%Y-%m-%d-%Hh-%Mm-%Ss.log')
|
||||
logging.basicConfig(filename=home() + '/.hmc-meetups/logs/' + logname, level=logging.INFO, format=f'%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s')
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.db = sqlite3.connect(home() + DATABASE)
|
||||
g.db.row_factory = sqlite3.Row
|
||||
|
||||
@app.teardown_request
|
||||
def teardown_request(exception):
|
||||
if hasattr(g, 'db'):
|
||||
g.db.close()
|
||||
|
||||
def insert_subscriber(email, agent, city):
|
||||
cur = g.db.cursor()
|
||||
creation_date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
query = '''
|
||||
INSERT INTO subscribers (
|
||||
email, creation_date, suppressed, suppressed_date, user_agent, city
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
cur.execute(query, (email, creation_date, 0, None, agent, city))
|
||||
g.db.commit() # @robustness @abner catch exceptions
|
||||
|
||||
@app.route('/v1/meetups/wishlist', methods=["POST"])
|
||||
def meetups_wishlist():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
city = request.form['city'] # @robustness @abner
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), city);
|
||||
app.logger.info("'" + address + "' has wishlisted '" + city + "'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/vienna', methods=["POST"])
|
||||
def meetups_vienna():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Vienna');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Vienna'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/denmark', methods=["POST"])
|
||||
def meetups_denmark():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Denmark');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Denmark'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/montreal', methods=["POST"])
|
||||
def meetups_montreal():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Montreal');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Montreal'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/revolt', methods=["POST"])
|
||||
def meetups_revolt():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Revolt');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Revolt'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/dc', methods=["POST"])
|
||||
def meetups_dc():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'D.C.');
|
||||
app.logger.info("'" + address + "' has subscribed to 'D.C.'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/vancouver', methods=["POST"])
|
||||
def meetups_vancouver():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Vancouver');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Vancouver'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/cambridge', methods=["POST"])
|
||||
def meetups_cambridge():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Cambridge');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Cambridge'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/atlanta', methods=["POST"])
|
||||
def meetups_atlanta():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Atlanta');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Atlanta'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/australia', methods=["POST"])
|
||||
def meetups_australia():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Australia');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Australia'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/tokyo', methods=["POST"])
|
||||
def meetups_tokyo():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Tokyo');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Tokyo'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/berlin', methods=["POST"])
|
||||
def meetups_berlin():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Berlin');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Berlin'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/termina', methods=["POST"])
|
||||
def meetups_termina():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Termina');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Termina'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/london', methods=["POST"])
|
||||
def meetups_london():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'London');
|
||||
app.logger.info("'" + address + "' has subscribed to 'London'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/seattle', methods=["POST"])
|
||||
def meetups_seattle():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Seattle');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Seattle'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/portland', methods=["POST"])
|
||||
def meetups_portland():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Portland');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Portland'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/boston', methods=["POST"])
|
||||
def meetups_boston():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Boston');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Boston'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/las_vegas', methods=["POST"])
|
||||
def meetups_las_vegas():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Las Vegas');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Las Vegas'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/san_francisco', methods=["POST"])
|
||||
def meetups_san_francisco():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'San Francisco');
|
||||
app.logger.info("'" + address + "' has subscribed to 'San Francisco'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/new_york_city', methods=["POST"])
|
||||
def meetups_new_york_city():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'New York City');
|
||||
app.logger.info("'" + address + "' has subscribed to 'New York City'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/detroit', methods=["POST"])
|
||||
def meetups_detroit():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Detroit');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Detroit'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/stockholm', methods=["POST"])
|
||||
def meetups_stockholm():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Stockholm');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Stockholm'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/gothenburg', methods=["POST"])
|
||||
def meetups_gothenburg():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Gothenburg');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Gothenburg'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/grenoble', methods=["POST"])
|
||||
def meetups_grenoble():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Grenoble');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Grenoble'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/israel', methods=["POST"])
|
||||
def meetups_israel():
|
||||
address = request.form['email'] # @robustness @abner what if it's empty?
|
||||
insert_subscriber(address, request.headers.get('User-Agent'), 'Israel');
|
||||
app.logger.info("'" + address + "' has subscribed to 'Israel'")
|
||||
return redirect(AGREEMENT_SUCCESS_URL);
|
||||
|
||||
@app.route('/v1/meetups/subscribers', methods=["POST"])
|
||||
def meetups_subscribers():
|
||||
# Verify headers
|
||||
|
||||
content_type = (
|
||||
request.headers['Content-Type'] if 'Content-Type' in request.headers else ''
|
||||
)
|
||||
|
||||
if 'application/json' in content_type:
|
||||
payload = request.json
|
||||
else:
|
||||
resp = { 'error' : 'JSON payload expected'}
|
||||
return make_response(jsonify(resp), 415)
|
||||
|
||||
# Confirm client version is compatible
|
||||
|
||||
if 'client' not in payload or payload['client'] != MEETUP_INVITE_CLIENT_VERSION:
|
||||
resp = { 'error' : 'Outdated client. Download latest version: https://git.handmadecities.com/meetups/meetupinvite2000/releases' }
|
||||
return make_response(jsonify(resp), 403)
|
||||
|
||||
# Extract city from POST request
|
||||
|
||||
if 'city' not in payload:
|
||||
resp = { 'error' : 'city field missing' }
|
||||
return make_response(jsonify(resp), 400)
|
||||
|
||||
city = payload['city']
|
||||
|
||||
app.logger.info('Received subscribers request with city \'' + city + '\'')
|
||||
|
||||
if city not in shared_secrets:
|
||||
resp = { 'error' : 'There are no official Handmade meetups in ' + city }
|
||||
return make_response(jsonify(resp), 400)
|
||||
|
||||
auth_header = ( request.headers['Authorization'] if 'Authorization' in request.headers else '')
|
||||
|
||||
if shared_secrets[city] not in auth_header:
|
||||
resp = { 'error' : 'wrong shared secret for ' + city }
|
||||
return make_response(jsonify(resp), 401)
|
||||
|
||||
# Query emails given the city
|
||||
cur = g.db.cursor()
|
||||
cur.execute('SELECT email FROM Subscribers WHERE city="' + city + '"')
|
||||
rows = cur.fetchall()
|
||||
|
||||
emails = [row[0] for row in rows]
|
||||
resp = { 'emails' : emails }
|
||||
|
||||
return make_response(jsonify(resp), 200)
|
||||
|
||||
@app.route('/v1/meetups/chat/invite', methods=["POST"])
|
||||
def meetups_chat_invite():
|
||||
content_type = (
|
||||
request.headers['Content-Type'] if 'Content-Type' in request.headers else ''
|
||||
)
|
||||
|
||||
if 'application/json' not in content_type:
|
||||
resp = { 'error': 'JSON payload expected' }
|
||||
return make_response(jsonify(resp), 415)
|
||||
|
||||
payload = request.json
|
||||
|
||||
if not payload or 'city' not in payload:
|
||||
resp = { 'error': 'city field missing' }
|
||||
return make_response(jsonify(resp), 400)
|
||||
|
||||
city = payload['city']
|
||||
app.logger.info('Received chat invite request for city \'' + city + '\'')
|
||||
|
||||
if city not in shared_secrets:
|
||||
resp = { 'error' : 'There are no official Handmade meetups in ' + city }
|
||||
return make_response(jsonify(resp), 400)
|
||||
|
||||
auth_header = ( request.headers['Authorization'] if 'Authorization' in request.headers else '')
|
||||
|
||||
if shared_secrets[city] not in auth_header:
|
||||
resp = { 'error' : 'wrong shared secret for ' + city }
|
||||
return make_response(jsonify(resp), 401)
|
||||
|
||||
# Pick a random invite code and return it
|
||||
|
||||
code = random.choice(INVITE_CODES)
|
||||
app.logger.info('Issued chat invite for ' + city + ': ' + code)
|
||||
resp = {
|
||||
'invite_code': code,
|
||||
# TODO(jmug): Verify with Abner is this is an actual secret.
|
||||
# NOTE(jmug): Request "revolt-invite-link" secret.
|
||||
'invite_link': '<redacted>',
|
||||
# NOTE(jmug): Request postmark-server-token secret.
|
||||
'postmark_server_token': '<redacted>',
|
||||
'postmark_template_id_register': 41923378,
|
||||
'postmark_template_id_join': 41930444
|
||||
}
|
||||
|
||||
return make_response(jsonify(resp), 200)
|
||||
|
||||
Reference in new issue
Block a user