Skip to content

Commit 69ed9e4

Browse files
committed
import debugproxy
This is a source dump from the debugproxy repository minus the deployment ansible code and load testing code. The history prior to this has been removed as it was too difficult to check if there was any sensitive information in it. Maybe it can be added later. Most of this code was writen 2 to 3 years ago and there have been a handful of commits since then fixing minor bugs and some minor updates in the deployment scripts.
1 parent 9145be9 commit 69ed9e4

352 files changed

Lines changed: 94039 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
bin
2+
/data
3+
include
4+
/lib
5+
/proxyui/dist
6+
share
7+
lib64
8+
.cache
9+
*.egg-info
10+
*__pycache__*
11+
pyvenv.cfg
12+
pip-selfcheck.json
13+
/proxyweb/static/gen/
14+
.webassets-cache
15+
tags
16+
.sass-cache
17+
*.pyc
18+
*.retry
19+

config/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from flask.config import Config
2+
import os
3+
import concurrent_log_handler
4+
5+
def read_config() -> Config:
6+
config = Config("")
7+
env_settings_file = os.environ.get('DEBUGPROXY_SETTING_FILE',
8+
'./config/default_settings.py')
9+
config.from_pyfile(env_settings_file)
10+
11+
# update the config with any values found in the environment
12+
for key in config.keys():
13+
env_value = os.environ.get(key)
14+
if env_value:
15+
config[key] = env_value
16+
17+
return config

config/default_settings.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# *****************************
2+
# Environment specific settings
3+
# *****************************
4+
5+
# Flask settings
6+
SECRET_KEY = 'een3Teinigh4BeeYaesh4ahtegheejei5Ooyeipeingi4thaho' # type: str
7+
8+
# SQLAlchemy settings
9+
SQLALCHEMY_DATABASE_URI = 'postgresql://postgres:password@localhost/website' # type: str
10+
11+
DATA_PATH = "./data"
12+
13+
# Flask-Mail settings
14+
MAIL_USERNAME = ''
15+
MAIL_PASSWORD = ''
16+
MAIL_DEFAULT_SENDER = ''
17+
MAIL_SERVER = ''
18+
MAIL_PORT = 587
19+
MAIL_USE_SSL = True
20+
MAIL_USE_TLS = True
21+
22+
LOG_FILE = '/tmp/website.log'
23+
24+
REDIS_HOST = "localhost"
25+
REDIS_PORT = "6379"
26+
27+
# Script / server urls
28+
PROXYUI_URL = 'http://localhost:4000/client/main.js'
29+
PROXYWEBSOCKET_URL = 'ws://localhost:8081/updates'
30+
PROXYSERVER_PORT = '8080'
31+
PROXYSERVER_URL = 'localhost:8080'
32+
PROXYWEBSOCKET_ZMQ_LISTEN_ADDRESS = 'tcp://127.0.0.1:5555'
33+
34+
PROXYSERVER_CHANNEL = 'channel:proxyserver'
35+
WEBSOCKET_CHANNEL = 'channel:websocket'
36+
WORKER_QUEUE = 'queue:workers'
37+
38+
WEBSITE_URL = "http://localhost:5000"
39+
DEBUG=True
40+
RELOAD=True
41+
42+
RATE_LIMITS = [
43+
(10000, 60 * 60),
44+
(5000, 10 * 60),
45+
(1000, 60),
46+
(50, 3)
47+
]
48+
49+
# Application settings
50+
APP_NAME = "debugproxy"
51+
APP_SYSTEM_ERROR_SUBJECT_LINE = APP_NAME + " system error"
52+
53+
# Flask settings
54+
CSRF_ENABLED = True
55+
56+
# Flask-User settings
57+
USER_APP_NAME = APP_NAME
58+
USER_ENABLE_CHANGE_PASSWORD = True # Allow users to change their password
59+
USER_ENABLE_CHANGE_USERNAME = False # Allow users to change their username
60+
USER_ENABLE_CONFIRM_EMAIL = True # Force users to confirm their email
61+
USER_ENABLE_FORGOT_PASSWORD = True # Allow users to reset their passwords
62+
USER_ENABLE_EMAIL = True # Register with Email
63+
USER_ENABLE_RETYPE_PASSWORD = True # Prompt for `retype password` in:
64+
USER_ENABLE_USERNAME = False # Register and Login with username
65+
USER_AFTER_LOGIN_ENDPOINT = 'home.home_page'
66+
USER_AFTER_LOGOUT_ENDPOINT = 'home.home_page'
67+
USER_ENABLE_REGISTRATION = True
68+
USER_ENABLE_INVITATION = True
69+
USER_REQUIRE_INVITATION = True
70+
USER_SEND_PASSWORD_CHANGED_EMAIL = False
71+
72+
TEMPLATES_AUTO_RELOAD = True

config/logging.ini

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[loggers]
2+
keys=root
3+
4+
[handlers]
5+
keys=stream_handler
6+
7+
[formatters]
8+
keys=formatter
9+
10+
[logger_root]
11+
level=DEBUG
12+
handlers=stream_handler
13+
14+
[handler_stream_handler]
15+
class=StreamHandler
16+
level=DEBUG
17+
formatter=formatter
18+
args=(sys.stderr,)
19+
20+
[formatter_formatter]
21+
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s

database/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from database.database import init_db, create_all, drop_all, session, Session

database/database.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from config import read_config
2+
3+
from sqlalchemy import create_engine
4+
from sqlalchemy.orm import scoped_session, sessionmaker
5+
from sqlalchemy.ext.declarative import declarative_base
6+
7+
8+
config = read_config()
9+
database_uri = config["SQLALCHEMY_DATABASE_URI"]
10+
11+
engine = create_engine(database_uri, convert_unicode=True)
12+
Session = sessionmaker(autocommit=False,
13+
autoflush=False,
14+
bind=engine)
15+
db_session = scoped_session(Session)
16+
session = db_session
17+
Base = declarative_base()
18+
Base.query = db_session.query_property()
19+
20+
def create_all():
21+
import database.models
22+
Base.metadata.create_all(bind=engine)
23+
24+
def drop_all():
25+
import database.models
26+
Base.metadata.drop_all(bind=engine)
27+
28+
def init_db():
29+
# import all modules here that might define models so that
30+
# they will be registered properly on the metadata. Otherwise
31+
# you will have to import them first before calling init_db()
32+
import database.models
33+
Base.metadata.create_all(bind=engine)

database/models.py

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
from datetime import datetime
2+
3+
from config import read_config
4+
from flask_user import UserMixin
5+
from itsdangerous import TimedJSONWebSignatureSerializer, SignatureExpired, \
6+
BadSignature
7+
import sqlalchemy as db
8+
from database.database import Base
9+
from sqlalchemy.orm import relationship, backref
10+
11+
config = read_config()
12+
13+
class Organization(Base):
14+
__tablename__ = 'organizations'
15+
id = db.Column(db.Integer, primary_key=True)
16+
name = db.Column(db.String(50),
17+
nullable=False,
18+
server_default=u'',
19+
unique=True)
20+
users = relationship('User', backref=backref('users'))
21+
22+
23+
class User(Base, UserMixin):
24+
__tablename__ = 'users'
25+
id = db.Column(db.Integer, primary_key=True)
26+
27+
# User authentication information (required for Flask-User)
28+
email = db.Column(db.Unicode(255),
29+
nullable=False,
30+
server_default=u'',
31+
unique=True)
32+
33+
confirmed_at = db.Column(db.DateTime())
34+
password = db.Column(db.String(255), nullable=False, server_default='')
35+
reset_password_token = db.Column(db.String(100),
36+
nullable=False,
37+
server_default='')
38+
39+
# User information
40+
active = db.Column('is_active',
41+
db.Boolean(),
42+
nullable=False,
43+
server_default='0')
44+
45+
first_name = db.Column(db.Unicode(50), nullable=False, server_default=u'')
46+
last_name = db.Column(db.Unicode(50), nullable=False, server_default=u'')
47+
48+
created_at = db.Column(db.DateTime(timezone=True), default=db.func.now())
49+
50+
# Relationships
51+
roles = relationship('Role', secondary='users_roles',
52+
backref=backref('users', lazy='dynamic'))
53+
54+
organization_id = db.Column(db.Integer(),
55+
db.ForeignKey('organizations.id',
56+
ondelete='CASCADE'),
57+
nullable=False)
58+
59+
proxy_sessions = relationship('ProxySession',
60+
cascade='all,delete',
61+
backref=backref('proxy_sessions'))
62+
63+
@property
64+
def is_admin(self) -> bool:
65+
return self.has_role('admin')
66+
67+
def generate_auth_token(self) -> str:
68+
sig = TimedJSONWebSignatureSerializer(
69+
config['SECRET_KEY'],
70+
expires_in=config['TOKEN_INVALIDATION_SECONDS']
71+
)
72+
return sig.dumps({'id':self.id})
73+
74+
@staticmethod
75+
def verify_auth_token(token: str) -> bool:
76+
s = TimedJSONWebSignatureSerializer(config['SECRET_KEY'])
77+
try:
78+
data = s.loads(token)
79+
except SignatureExpired:
80+
return None
81+
except BadSignature:
82+
return None
83+
return User.get_by_id(data['id'])
84+
85+
@classmethod
86+
def get_by_id(cls, record_id: str) -> Base:
87+
if any(
88+
(isinstance(record_id, str) and record_id.isdigit(),
89+
isinstance(record_id, (int, float))),
90+
):
91+
return cls.query.get(int(record_id))
92+
return None
93+
94+
95+
class ProxySession(Base):
96+
__tablename__ = 'proxy_session'
97+
id = db.Column(db.Integer(), primary_key=True)
98+
99+
user_id = db.Column(db.Integer(),
100+
db.ForeignKey('users.id',
101+
ondelete='CASCADE'),
102+
nullable=False)
103+
104+
username = db.Column(db.String(255),
105+
nullable=False,
106+
unique=True)
107+
108+
password = db.Column(db.String(255),
109+
nullable=False)
110+
111+
is_active = db.Column(db.Boolean(),
112+
nullable=False,
113+
server_default='1')
114+
115+
requests = relationship('Request',
116+
cascade="all,delete",
117+
backref=backref('requests'))
118+
119+
intercepts = relationship('Intercept',
120+
cascade="all,delete",
121+
backref=backref('intercepts'))
122+
123+
created_at = db.Column(db.DateTime(timezone=True), default=db.func.now())
124+
updated_at = db.Column(db.DateTime(timezone=True), default=db.func.now())
125+
126+
127+
class Intercept(Base):
128+
__tablename__ = 'intercept'
129+
130+
id = db.Column(db.Integer(), primary_key=True)
131+
132+
session_id = db.Column(db.Integer(),
133+
db.ForeignKey('proxy_session.id',
134+
ondelete='CASCADE'),
135+
nullable=False)
136+
137+
query = db.Column(db.String(255),
138+
nullable=False)
139+
140+
method = db.Column(db.String(255),
141+
nullable=False)
142+
143+
# CREATE INDEX CONCURRENTLY request_key_index ON request (key);
144+
# CREATE INDEX CONCURRENTLY request_session_id_index ON request (session_id);
145+
# CREATE INDEX CONCURRENTLY request_created_at_index ON request (created_at);
146+
# ALTER TABLE request SET (autovacuum_vacuum_scale_factor = 0.0);
147+
# ALTER TABLE request SET (autovacuum_vacuum_threshold = 5000);
148+
# ALTER TABLE request SET (autovacuum_analyze_scale_factor = 0.0);
149+
# ALTER TABLE request SET (autovacuum_analyze_threshold = 5000);
150+
151+
class Request(Base):
152+
__tablename__ = 'request'
153+
154+
id = db.Column(db.Integer(), primary_key=True)
155+
156+
key = db.Column(db.String(255),
157+
nullable=False)
158+
159+
session_id = db.Column(db.Integer(),
160+
db.ForeignKey('proxy_session.id',
161+
ondelete='CASCADE'),
162+
nullable=False)
163+
164+
state = db.Column(db.JSON())
165+
proxyserver = db.Column(db.String(50), nullable=False)
166+
created_at = db.Column(db.DateTime(timezone=True), default=db.func.now())
167+
168+
169+
class Role(Base):
170+
__tablename__ = 'roles'
171+
id = db.Column(db.Integer(), primary_key=True)
172+
name = db.Column(db.String(50), nullable=False, server_default=u'', unique=True) # for @roles_accepted()
173+
label = db.Column(db.Unicode(255), server_default=u'') # for display purposes
174+
175+
176+
class UsersRoles(Base):
177+
__tablename__ = 'users_roles'
178+
id = db.Column(db.Integer(), primary_key=True)
179+
user_id = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
180+
role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
181+
182+
183+
class UserInvitation(Base):
184+
__tablename__ = 'user_invite'
185+
id = db.Column(db.Integer, primary_key=True)
186+
email = db.Column(db.String(255), nullable=False)
187+
# save the user of the invitee
188+
invited_by_user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
189+
# token used for registration page to identify user registering
190+
token = db.Column(db.String(100), nullable=False, server_default='')
191+
created_at = db.Column(db.DateTime(timezone=True), default=db.func.now())

default.nix

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
with import <nixpkgs> {};
2+
let
3+
my-python-packages = python-packages: [
4+
python-packages.pip
5+
python-packages.setuptools
6+
];
7+
my-python = python37.withPackages my-python-packages;
8+
in
9+
pkgs.mkShell {
10+
buildInputs = [
11+
bashInteractive
12+
my-python
13+
libffi
14+
openssl
15+
libxml2
16+
postgresql
17+
libxslt
18+
sass
19+
nodejs
20+
];
21+
shellHook = ''
22+
export PATH=$PATH:"$(pwd)/.build/pip_packages/bin"
23+
export PIP_PREFIX="$(pwd)/.build/pip_packages"
24+
export PYTHONPATH="$(pwd)/.build/pip_packages/bin:$PYTHONPATH"
25+
export PYTHONPATH="$(pwd)/.build/pip_packages/lib/python3.7/site-packages:$PYTHONPATH"
26+
unset SOURCE_DATE_EPOCH
27+
'';
28+
}

0 commit comments

Comments
 (0)