Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bringing in latest from upstream repo #40

Merged
merged 57 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1e1b189
Remove py3.7 (#234)
yurushao Jun 9, 2023
6f02f6e
Bump cryptography from 39.0.2 to 41.0.1 (#260)
dependabot[bot] Jun 9, 2023
013c0d1
Bump tox from 3.25.0 to 4.6.0 (#262)
dependabot[bot] Jun 9, 2023
95f5c35
Bump fakeredis from 1.7.5 to 2.14.1 (#263)
dependabot[bot] Jun 9, 2023
147bdf3
Bump flask from 2.1.2 to 2.3.2 (#250)
dependabot[bot] Jun 9, 2023
6fec10e
Bump pytest from 7.1.2 to 7.3.1 (#243)
dependabot[bot] Jun 9, 2023
a34aaf8
Bump redis from 4.5.3 to 4.5.5 (#253)
dependabot[bot] Jun 9, 2023
5725b0d
Bump coverage from 6.4.1 to 7.2.7 (#267)
dependabot[bot] Jun 12, 2023
4c118cf
Bump pytest-cov from 3.0.0 to 4.1.0 (#266)
dependabot[bot] Jun 12, 2023
9d68d6b
Bump actions/checkout from 3 to 4 (#282)
dependabot[bot] Sep 25, 2023
31ae18d
[Snyk] Security upgrade cryptography from 41.0.1 to 41.0.4 (#284)
devinlundberg Sep 25, 2023
f3edccd
Bump tox from 4.6.0 to 4.11.3 (#287)
dependabot[bot] Sep 26, 2023
03bf76f
Bump fakeredis from 2.14.1 to 2.20.0
dependabot[bot] Oct 23, 2023
c4d6074
Merge pull request #292 from pinterest/dependabot/pip/fakeredis-2.20.0
xia0pin9 Oct 23, 2023
1a9824d
Bump redis from 4.5.5 to 5.0.1
dependabot[bot] Oct 23, 2023
6a10fd3
Merge pull request #289 from pinterest/dependabot/pip/redis-5.0.1
xia0pin9 Oct 23, 2023
99028bf
Install deps from requirements.txt (#303)
yurushao Dec 1, 2023
baa921f
Prepare 1.6.1 release (#304)
yurushao Dec 2, 2023
8103cb4
Bump version: 1.6.0 → 1.6.1 (#305)
yurushao Dec 2, 2023
ae27473
Use urllib.parse for quoting/unquoting plus instead of deprecated wer…
vin01 Dec 2, 2023
fd27ab7
Bump actions/setup-python from 4 to 5 (#306)
dependabot[bot] Dec 22, 2023
b53ceed
Bump github/codeql-action from 2 to 3 (#309)
dependabot[bot] Dec 22, 2023
b66b1e1
Bump werkzeug from 2.3.3 to 3.0.1 (#295)
dependabot[bot] Dec 22, 2023
7db0be7
Bump flask from 2.3.2 to 3.0.0 (#294)
dependabot[bot] Dec 22, 2023
3871c39
Bump pytest from 7.3.1 to 7.4.4
dependabot[bot] Jan 1, 2024
a8e4312
Bump version: 1.6.1 → 1.6.2 (#311)
yurushao Jan 3, 2024
29ce62b
Merge pull request #314 from pinterest/dependabot/pip/pytest-7.4.4
xia0pin9 Jan 3, 2024
6798a26
Bump freezegun from 1.2.1 to 1.4.0
dependabot[bot] Jan 3, 2024
564a29d
Merge pull request #312 from pinterest/dependabot/pip/freezegun-1.4.0
xia0pin9 Jan 3, 2024
d8c05a9
Bump flake8 from 6.0.0 to 7.0.0
dependabot[bot] Jan 5, 2024
74ded41
Merge pull request #315 from pinterest/dependabot/pip/flake8-7.0.0
xia0pin9 Jan 5, 2024
455db36
Add health check endpoint (#329)
yurushao Feb 3, 2024
6d294c6
add i18n to Snappass
systeembeheerder Feb 14, 2024
62a6290
Bump fakeredis from 2.20.0 to 2.21.1
dependabot[bot] Feb 16, 2024
6d17603
remove import of flask, g
systeembeheerder Feb 16, 2024
d178664
Add empty translations for de and es
systeembeheerder Feb 16, 2024
49de2bc
Bump cryptography from 41.0.4 to 42.0.3
dependabot[bot] Feb 19, 2024
28c396e
Add German Translation
systeembeheerder Feb 19, 2024
fcfc1b0
Merge pull request #331 from pinterest/dependabot/pip/fakeredis-2.21.1
xia0pin9 Feb 20, 2024
e0b8245
Bump pytest from 7.4.4 to 8.0.1
dependabot[bot] Feb 20, 2024
0084d85
Merge pull request #332 from pinterest/dependabot/pip/cryptography-42…
xia0pin9 Feb 20, 2024
f551b73
Merge pull request #334 from pinterest/dependabot/pip/pytest-8.0.1
xia0pin9 Feb 20, 2024
3cba966
Bump coverage from 7.2.7 to 7.4.2
dependabot[bot] Feb 20, 2024
82c345c
Merge pull request #335 from pinterest/dependabot/pip/coverage-7.4.2
xia0pin9 Feb 20, 2024
ba67b42
Bump tox from 4.11.3 to 4.13.0
dependabot[bot] Feb 20, 2024
415d5ee
Merge pull request #333 from pinterest/dependabot/pip/tox-4.13.0
xia0pin9 Feb 21, 2024
9fdddab
fix missing bracket
systeembeheerder Feb 21, 2024
4fffb9c
restore extra spaces
systeembeheerder Feb 22, 2024
114b5af
Add Spanish and fixup NL&DE
systeembeheerder Feb 22, 2024
106ac26
TIL flake8 :)
systeembeheerder Feb 23, 2024
2b108d3
Merge pull request #330 from systeembeheerder/i18n
xia0pin9 Feb 23, 2024
5d37e45
Bump actions/cache from 3 to 4 (#320)
dependabot[bot] Feb 23, 2024
04f9402
Bump jinja2 from 3.1.2 to 3.1.3 (#336)
dependabot[bot] Feb 23, 2024
dc321ef
add /api endpoint for automated flows (#316)
reinoud Feb 26, 2024
838cdf6
Bump pytest from 8.0.1 to 8.1.0
dependabot[bot] Mar 4, 2024
9c233c0
Merge pull request #339 from pinterest/dependabot/pip/pytest-8.1.0
xia0pin9 Mar 4, 2024
0caa06f
Merge branch 'master' of https://github.com/pinterest/snappass into l…
silverl Mar 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-python-${{ matrix.python-version }}-pip-${{ hashFiles('.github/workflows/ci.yml') }}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ htmlcov/
# virtualenv
venv/
ENV/

# Translation catalogs
*.mo
*.pot
34 changes: 34 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,40 @@ need to change this.

``HOST_OVERRIDE``: (optional) Used to override the base URL if the app is unaware. Useful when running behind reverse proxies like an identity-aware SSO. Example: ``sub.domain.com``

API
---

SnapPass also has a simple API that can be used to create passwords links. The advantage of using the API is that
you can create a password and retrieve the link without having to open the web interface. This is useful if you want to
embed it in a script or use it in a CI/CD pipeline.

To create a password, send a POST request to ``/api/set_password`` like so:

::

$ curl -X POST -H "Content-Type: application/json" -d '{"password": "foobar"}' http://localhost:5000/api/set_password/

This will return a JSON response with the password link:

::

{
"link": "http://127.0.0.1:5000/snappassbedf19b161794fd288faec3eba15fa41~hHnILpQ50ZfJc3nurDfHCb_22rBr5gGEya68e_cZOrY%3D",
"ttl":1209600
}

the default TTL is 2 weeks (1209600 seconds), but you can override it by adding a expiration parameter:

::

$ curl -X POST -H "Content-Type: application/json" -d '{"password": "foobar", "ttl": 3600 }' http://localhost:5000/api/set_password/

Notes:

- When using the API, you can specify any ttl, as long as it is lower than the default.
- The password is passed in the body of the request rather than in the URL. This is to prevent the password from being logged in the server logs.
- Depending on the environment you are running it, you might want to expose the ``/api`` endpoint to your internal network only, and put the web interface behind authentication.

Docker
------

Expand Down
10 changes: 10 additions & 0 deletions babel.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Update Translations:
# (venv) $ pybabel extract -F babel.cfg -o messages.pot .
# (venv) $ pybabel update -i messages.pot -d snappass/translations
# (venv) $ pybabel compile -d snappass/translations
# Add a new language:
# (venv) $ pybabel extract -F babel.cfg -o messages.pot .
# (venv) $ pybabel init -i messages.pot -d snappass/translations -l <language_code>
[python: snappass/**.py]
[jinja2: snappass/templates/**.html]

8 changes: 4 additions & 4 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
coverage==7.2.7
fakeredis==2.20.0
coverage==7.4.2
fakeredis==2.21.1
flake8==7.0.0
freezegun==1.4.0
pytest==7.4.4
pytest==8.1.0
pytest-cov==4.1.0
tox==4.11.3
tox==4.13.0
bumpversion==0.6.0
wheel==0.42.0
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
cryptography==42.0.0
cryptography==42.0.3
Flask==3.0.0
itsdangerous==2.1.2
Jinja2==3.1.3
MarkupSafe==2.1.1
redis==5.0.1
Werkzeug==3.0.1
flask-babel
70 changes: 53 additions & 17 deletions snappass/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
from urllib.parse import quote_plus
from urllib.parse import unquote_plus
from distutils.util import strtobool
from flask_babel import Babel

NO_SSL = bool(strtobool(os.environ.get('NO_SSL', 'False')))
URL_PREFIX = os.environ.get('URL_PREFIX', None)
HOST_OVERRIDE = os.environ.get('HOST_OVERRIDE', None)
TOKEN_SEPARATOR = '~'


# Initialize Flask Application
app = Flask(__name__)
if os.environ.get('DEBUG'):
Expand All @@ -25,9 +25,18 @@
app.config.update(
dict(STATIC_URL=os.environ.get('STATIC_URL', 'static')))


# Set up Babel
def get_locale():
return request.accept_languages.best_match(['en', 'es', 'de', 'nl'])


babel = Babel(app, locale_selector=get_locale)

# Initialize Redis
if os.environ.get('MOCK_REDIS'):
from fakeredis import FakeStrictRedis

redis_client = FakeStrictRedis()
elif os.environ.get('REDIS_URL'):
redis_client = redis.StrictRedis.from_url(os.environ.get('REDIS_URL'))
Expand All @@ -39,7 +48,10 @@
host=redis_host, port=redis_port, db=redis_db)
REDIS_PREFIX = os.environ.get('REDIS_PREFIX', 'snappass')

TIME_CONVERSION = {'two weeks': 1209600, 'week': 604800, 'day': 86400, 'hour': 3600}
TIME_CONVERSION = {'two weeks': 1209600, 'week': 604800, 'day': 86400,
'hour': 3600}
DEFAULT_API_TTL = 1209600
MAX_TTL = DEFAULT_API_TTL


def check_redis_alive(fn):
Expand All @@ -54,6 +66,7 @@ def inner(*args, **kwargs):
sys.exit(0)
else:
return abort(500)

return inner


Expand Down Expand Up @@ -154,33 +167,56 @@ def clean_input():
return TIME_CONVERSION[time_period], request.form['password']


@app.route('/', methods=['GET'])
def index():
return render_template('set_password.html')


@app.route('/', methods=['POST'])
def handle_password():
ttl, password = clean_input()
token = set_password(password, ttl)

def set_base_url(req):
if NO_SSL:
if HOST_OVERRIDE:
base_url = f'http://{HOST_OVERRIDE}/'
else:
base_url = request.url_root
base_url = req.url_root
else:
if HOST_OVERRIDE:
base_url = f'https://{HOST_OVERRIDE}/'
else:
base_url = request.url_root.replace("http://", "https://")
base_url = req.url_root.replace("http://", "https://")
if URL_PREFIX:
base_url = base_url + URL_PREFIX.strip("/") + "/"
link = base_url + quote_plus(token)
if request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html:
return base_url


@app.route('/', methods=['GET'])
def index():
return render_template('set_password.html')


@app.route('/', methods=['POST'])
def handle_password():
password = request.form.get('password')
ttl = request.form.get('ttl')
if clean_input():
ttl = TIME_CONVERSION[ttl.lower()]
token = set_password(password, ttl)
base_url = set_base_url(request)
link = base_url + quote_plus(token)
if request.accept_mimetypes.accept_json and not \
request.accept_mimetypes.accept_html:
return jsonify(link=link, ttl=ttl)
else:
return render_template('confirm.html', password_link=link)
else:
abort(500)


@app.route('/api/set_password/', methods=['POST'])
def api_handle_password():
password = request.json.get('password')
ttl = int(request.json.get('ttl', DEFAULT_API_TTL))
if password and isinstance(ttl, int) and ttl <= MAX_TTL:
token = set_password(password, ttl)
base_url = set_base_url(request)
link = base_url + quote_plus(token)
return jsonify(link=link, ttl=ttl)
else:
return render_template('confirm.html', password_link=link)
abort(500)


@app.route('/<password_key>', methods=['GET'])
Expand Down
12 changes: 5 additions & 7 deletions snappass/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title>TrackAbout Snappass - Secret Sharing Service</title>
<html lang="{{ _('en') }}">
<head>
<title>{{ _('TrackAbout Snappass - Secret Sharing Service') }}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Expand All @@ -16,10 +15,9 @@
<div class="container">
<div class="navbar-header">
<div style="margin-top:15px">
<a class="logo"><img src="static/ta-logo.png"></img>
</a>
<a class="logo"><img src="static/ta-logo.png" /></a>
</div>
<a class="navbar-brand" href="/">Secret Sharing Service</a>
<a class="navbar-brand" href="/">{{ _('Share Secret') }}</a>
</div>
</div>
</nav>
Expand Down
6 changes: 3 additions & 3 deletions snappass/templates/confirm.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
{% block content %}
<div class="container">
<section>
<div class="page-header"><h1>Share Secret Link</h1></div>
<p>The secret has been temporarily saved. Send the following URL to your intended recipient.</p>
<div class="page-header"><h1>{{ _('Share Secret Link') }}</h1></div>
<p>{{ _('The secret has been temporarily saved. Send the following URL to your intended recipient.') }}</p>
<div class="row">
<div class="col-sm-6 margin-bottom-10">
<input type="text" class="form-control" id="password-link" value="{{ password_link }}" readonly="readonly">
</div>

<div class="col-sm-6">
<button title="Copy to clipboard" type="button" class="btn btn-primary copy-clipboard-btn"
<button title="{{ _('Copy to clipboard') }}" type="button" class="btn btn-primary copy-clipboard-btn"
id="copy-clipboard-btn" data-clipboard-target="#password-link"
data-placement='bottom'>
<i class="fa fa-clipboard"></i>
Expand Down
6 changes: 3 additions & 3 deletions snappass/templates/expired.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
{% block content %}
<div class="container">
<section>
<div class="page-header"><h1>Secret not found</h1></div>
<p class="lead">The requested URL was not found on the server. This could be because this URL never contained a secret, or because it expired or was revealed earlier.</p>
<p class="lead">If this URL was sent to you by someone, make sure to check your spelling or ask the person who sent it to you to send a new secret.</p>
<div class="page-header"><h1>{{ _('Secret not found') }}</h1></div>
<p class="lead">{{ _('The requested URL was not found on the server. This could be because this URL never contained a secret, or because it expired or was revealed earlier.') }}</p>
<p class="lead">{{ _('If this URL was sent to you by someone, make sure to check your spelling or ask the person who sent it to you to send a new secret.') }}</p>
</section>
</div>
{% endblock %}
8 changes: 4 additions & 4 deletions snappass/templates/password.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
{% block content %}
<div class="container">
<section>
<div class="page-header"><h1>Secret</h1></div>
<p>Save the following secret to a secure location.</p>
<div class="page-header"><h1>{{ _('Secret') }}</h1></div>
<p>{{ _('Save the following secret to a secure location.') }}</p>
<div class="row">
<div class="col-sm-6 margin-bottom-10">
<textarea class="form-control" rows="10" cols="50" id="password-text" name="password-text" readonly="readonly">{{ password }}</textarea>
</div>

<div class="col-sm-6">
<button title="Copy to clipboard" type="button" class="btn btn-primary copy-clipboard-btn"
<button title="{{ _('Copy to clipboard') }}" type="button" class="btn btn-primary copy-clipboard-btn"
id="copy-clipboard-btn" data-clipboard-target="#password-text"
data-placement='bottom'>
<i class="fa fa-clipboard"></i>
</button>
</div>
</div>
<p>The secret has now been permanently deleted from the system, and the URL will no longer work. Refresh this page to verify.</p>
<p>{{ _('The secret has now been permanently deleted from the system, and the URL will no longer work. Refresh this page to verify.') }}</p>
</section>
</div>
{% endblock %}
Expand Down
8 changes: 4 additions & 4 deletions snappass/templates/preview.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
<div class="container">
<section>
<div class="page-header">
<h1>Secret</h1>
<h1>{{ _('Secret') }}</h1>
</div>
<p class="lead">You can only reveal the secret once!</p>
<p class="lead">{{ _('You can only reveal the secret once!') }}</p>
<div class="row">
<div class="col-sm-6 margin-bottom-10">
<button id="revealSecret" type="button" class="btn-lg btn-primary">Reveal secret</button>
<button id="revealSecret" type="button" class="btn-lg btn-primary">{{ _('Reveal secret') }}</button>
</div>
</div>
</section>
Expand All @@ -20,4 +20,4 @@ <h1>Secret</h1>
<script src="{{ config.STATIC_URL }}/clipboardjs/clipboard.min.js"></script>
<script src="{{ config.STATIC_URL }}/snappass/scripts/clipboard_button.js"></script>
<script src="{{ config.STATIC_URL }}/snappass/scripts/preview.js"></script>
{% endblock %}
{% endblock %}
14 changes: 7 additions & 7 deletions snappass/templates/set_password.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@
{% block content %}
<div class="container">
<section>
<div class="page-header"><h1>Set Secret</h1></div>
<div class="page-header"><h1>{{ _('Set Secret') }}</h1></div>
<div class="row">
<form role="form" id="password_create" method="post" autocomplete="off">
<div class="col-sm-6 margin-bottom-10">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></span>
<textarea rows="10" cols="50" id="password" name="password" autofocus="true" class="form-control" placeholder="This service allows you to share secrets in a secure, ephemeral way. Input a single or multi-line secret, its expiration time, and click Generate URL. Share the one-time use URL with your intended recipient." aria-describedby="basic-addon1" autocomplete="off" required></textarea>
<textarea rows="10" cols="50" id="password" name="password" autofocus="true" class="form-control" placeholder="{{ _('SnapPass allows you to share secrets in a secure, ephemeral way. Input a single or multi-line secret, its expiration time, and click Generate URL. Share the one-time use URL with your intended recipient.') }}" aria-describedby="basic-addon1" autocomplete="off" required></textarea>
</div>
</div>

<div class="col-sm-2 margin-bottom-10">
<select class="form-control" name="ttl">
<option value="Two Weeks">Two Weeks</option>
<option value="Week" selected="selected">Week</option>
<option value="Day">Day</option>
<option value="Hour">Hour</option>
<option value="Two Weeks">{{ _('Two Weeks') }}</option>
<option value="Week" selected="selected">{{ _('Week') }}</option>
<option value="Day">{{ _('Day') }}</option>
<option value="Hour">{{ _('Hour') }}</option>
</select>
</div>

<div class="col-sm-4">
<button type="submit" class="btn btn-primary" id="submit">Generate URL</button>
<button type="submit" class="btn btn-primary" id="submit">{{ _('Generate URL') }}</button>
</div>
</form>
</div>
Expand Down
Loading
Loading