Compare commits
10 Commits
d3371b1aae
...
886458fb29
Author | SHA1 | Date | |
---|---|---|---|
886458fb29 | |||
b310357fa8 | |||
6769fdd435 | |||
cc4d3fffcd | |||
fcec32baea | |||
509201aa37 | |||
57014c8b44 | |||
6af38a12f8 | |||
2c734135eb | |||
a015ef776d |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.sw*
|
||||
.DS_Store
|
@ -1,4 +1,4 @@
|
||||
pipeline:
|
||||
steps:
|
||||
buildweb:
|
||||
group: build
|
||||
image: node
|
||||
@ -32,5 +32,6 @@ pipeline:
|
||||
- s3cmd --configure --access_key=$LINODE_ACCESS_KEY --secret_key=$LINODE_SECRET_ACCESS_KEY --host=https://eu-central-1.linodeobjects.com --host-bucket="%(bucket)s.eu-central-1.linodeobjects.com" --dump-config > /root/.s3cfg
|
||||
- s3cmd -c /root/.s3cfg sync --no-mime-magic --guess-mime-type dist/* s3://dotty.cloud
|
||||
- 'curl -X POST -H "AccessKey: $BUNNY_KEY" https://api.bunny.net/pullzone/782735/purgeCache'
|
||||
|
||||
branches: main
|
||||
|
||||
when:
|
||||
branch: main
|
||||
|
151
api/accounts.py
151
api/accounts.py
@ -1,78 +1,109 @@
|
||||
import os, datetime, hashlib
|
||||
import os
|
||||
import datetime
|
||||
import hashlib
|
||||
from flask import jsonify
|
||||
from bson.objectid import ObjectId
|
||||
import jwt, bcrypt
|
||||
import jwt
|
||||
import bcrypt
|
||||
from util import database
|
||||
|
||||
jwt_secret = os.environ.get('JWT_SECRET')
|
||||
jwt_secret = os.environ.get("JWT_SECRET")
|
||||
|
||||
|
||||
def get_user_context(request, token):
|
||||
if not token: return None
|
||||
try:
|
||||
id = jwt.decode(token, jwt_secret, algorithms=['HS256'])['sub']
|
||||
if id:
|
||||
db = database.get_db()
|
||||
user = db.users.find_one({'_id': ObjectId(id), 'keys': token})
|
||||
if user: user['currentToken'] = token
|
||||
return user
|
||||
except Exception as e:
|
||||
return None
|
||||
if not token:
|
||||
return None
|
||||
try:
|
||||
id = jwt.decode(token, jwt_secret, algorithms=["HS256"])["sub"]
|
||||
if id:
|
||||
db = database.get_db()
|
||||
user = db.users.find_one({"_id": ObjectId(id), "keys": token})
|
||||
if user:
|
||||
user["currentToken"] = token
|
||||
return user
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def generate_api_token(user_id):
|
||||
payload = {
|
||||
'iat': datetime.datetime.utcnow(),
|
||||
'sub': str(user_id)
|
||||
}
|
||||
return jwt.encode(payload, jwt_secret, algorithm='HS256')
|
||||
payload = {"iat": datetime.datetime.utcnow(), "sub": str(user_id)}
|
||||
return jwt.encode(payload, jwt_secret, algorithm="HS256")
|
||||
|
||||
|
||||
def create(data):
|
||||
if not data:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
email = data.get('email', '').lower().strip()
|
||||
password = data.get('password', '')
|
||||
db = database.get_db()
|
||||
existing = db.users.find_one({'email': email})
|
||||
if not email or not password:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
if existing:
|
||||
return jsonify({'success': False, 'message': 'An account with that email address already exists'}), 400
|
||||
hashed_password = bcrypt.hashpw(hashlib.sha256(password.encode('utf-8')).hexdigest().encode('utf-8'), bcrypt.gensalt())
|
||||
user_id = ObjectId()
|
||||
token = generate_api_token(user_id)
|
||||
db.users.insert_one({'_id': user_id, 'email': email, 'password': hashed_password.decode('utf-8'), 'createdAt': datetime.datetime.utcnow(), 'keys': [token]})
|
||||
return token
|
||||
if not data:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
email = data.get("email", "").lower().strip()
|
||||
password = data.get("password", "")
|
||||
db = database.get_db()
|
||||
existing = db.users.find_one({"email": email})
|
||||
if not email or not password:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
if existing:
|
||||
return jsonify(
|
||||
{
|
||||
"success": False,
|
||||
"message": "An account with that email address already exists",
|
||||
}
|
||||
), 400
|
||||
hashed_password = bcrypt.hashpw(
|
||||
hashlib.sha256(password.encode("utf-8")).hexdigest().encode("utf-8"),
|
||||
bcrypt.gensalt(),
|
||||
)
|
||||
user_id = ObjectId()
|
||||
token = generate_api_token(user_id)
|
||||
db.users.insert_one(
|
||||
{
|
||||
"_id": user_id,
|
||||
"email": email,
|
||||
"password": hashed_password.decode("utf-8"),
|
||||
"createdAt": datetime.datetime.utcnow(),
|
||||
"keys": [token],
|
||||
}
|
||||
)
|
||||
return token
|
||||
|
||||
|
||||
def login(data):
|
||||
if not data:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
email = data.get('email', '').lower().strip()
|
||||
password = data.get('password', '')
|
||||
if not email or not password:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
db = database.get_db()
|
||||
existing = db.users.find_one({'email': email})
|
||||
if not existing:
|
||||
return jsonify({'success': False, 'message': 'Email address or password incorrect'}), 400
|
||||
|
||||
incoming_pw = hashlib.sha256(data['password'].encode('utf-8')).hexdigest()
|
||||
if bcrypt.checkpw(incoming_pw.encode('utf-8'), existing['password'].encode('utf-8')):
|
||||
token = generate_api_token(existing['_id'])
|
||||
db.users.update_one({'_id': existing['_id']}, {'$addToSet': {'keys': token}})
|
||||
return token
|
||||
return jsonify({'success': False, 'message': 'Email address or password incorrect'}), 400
|
||||
if not data:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
email = data.get("email", "").lower().strip()
|
||||
password = data.get("password", "")
|
||||
if not email or not password:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
db = database.get_db()
|
||||
existing = db.users.find_one({"email": email})
|
||||
if not existing:
|
||||
return jsonify(
|
||||
{"success": False, "message": "Email address or password incorrect"}
|
||||
), 400
|
||||
|
||||
incoming_pw = hashlib.sha256(data["password"].encode("utf-8")).hexdigest()
|
||||
if bcrypt.checkpw(
|
||||
incoming_pw.encode("utf-8"), existing["password"].encode("utf-8")
|
||||
):
|
||||
token = generate_api_token(existing["_id"])
|
||||
db.users.update_one({"_id": existing["_id"]}, {"$addToSet": {"keys": token}})
|
||||
return token
|
||||
return jsonify(
|
||||
{"success": False, "message": "Email address or password incorrect"}
|
||||
), 400
|
||||
|
||||
|
||||
def logout(user):
|
||||
db = database.get_db()
|
||||
db.users.update_one({'_id': user['_id']}, {'$pull': {'keys': user['currentToken']}})
|
||||
return jsonify({'success': True}), 200
|
||||
db = database.get_db()
|
||||
db.users.update_one({"_id": user["_id"]}, {"$pull": {"keys": user["currentToken"]}})
|
||||
return jsonify({"success": True}), 200
|
||||
|
||||
|
||||
def logout_others(user):
|
||||
db = database.get_db()
|
||||
keys = filter(lambda k: k != user['currentToken'], user.get('keys', []))
|
||||
db.users.update_one({'_id': user['_id']}, {'$set': {'keys': list(keys)}})
|
||||
return jsonify({'success': True}), 200
|
||||
db = database.get_db()
|
||||
keys = filter(lambda k: k != user["currentToken"], user.get("keys", []))
|
||||
db.users.update_one({"_id": user["_id"]}, {"$set": {"keys": list(keys)}})
|
||||
return jsonify({"success": True}), 200
|
||||
|
||||
|
||||
def logout_all(user):
|
||||
db = database.get_db()
|
||||
db.users.update_one({'_id': user['_id']}, {'$set': {'keys': []}})
|
||||
return jsonify({'success': True}), 200
|
||||
db = database.get_db()
|
||||
db.users.update_one({"_id": user["_id"]}, {"$set": {"keys": []}})
|
||||
return jsonify({"success": True}), 200
|
||||
|
127
api/app.py
127
api/app.py
@ -1,64 +1,123 @@
|
||||
import sentry_sdk
|
||||
from flask import Flask, jsonify, request, g
|
||||
from webargs import fields, validate
|
||||
from webargs.flaskparser import use_args
|
||||
from util import util
|
||||
import files, accounts, passwords
|
||||
import files
|
||||
import accounts
|
||||
import passwords
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn="https://6a7be9c67251f0b715d7d477c5ae2cef@o4508066290532352.ingest.de.sentry.io/4508070957875280",
|
||||
traces_sample_rate=1.0,
|
||||
profiles_sample_rate=1.0,
|
||||
)
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Error handlers
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def handle_404(e):
|
||||
return jsonify({'message': 'Resource not found'}), 404
|
||||
return jsonify({"message": "Resource not found"}), 404
|
||||
|
||||
|
||||
@app.errorhandler(422)
|
||||
def handle_unprocessable_entity(e):
|
||||
return jsonify(
|
||||
{
|
||||
"validations": e.data.get("messages"),
|
||||
}
|
||||
), 422
|
||||
|
||||
|
||||
@app.errorhandler(429)
|
||||
def handle_429(e):
|
||||
return jsonify({'message': 'Rate limit exceeded', 'Allowed limit': e.description}), 429
|
||||
return jsonify(
|
||||
{"message": "Rate limit exceeded", "Allowed limit": e.description}
|
||||
), 429
|
||||
|
||||
|
||||
@app.errorhandler(500)
|
||||
def handle_500():
|
||||
return jsonify({'message': 'There was a problem with this request. Please try again later.'}), 500
|
||||
return jsonify(
|
||||
{"message": "There was a problem with this request. Please try again later."}
|
||||
), 500
|
||||
|
||||
@app.route('/accounts', methods=['POST'])
|
||||
def accounts_route():
|
||||
if request.method == 'POST':
|
||||
return accounts.create(request.get_json())
|
||||
|
||||
@app.route('/accounts/password/tokens', methods=['POST', 'PUT'])
|
||||
# Route handlers
|
||||
|
||||
|
||||
@app.route("/accounts", methods=["POST"])
|
||||
@use_args(
|
||||
{
|
||||
"email": fields.Email(required=True),
|
||||
"password": fields.Str(required=True, validate=validate.Length(min=8)),
|
||||
}
|
||||
)
|
||||
def accounts_route(args):
|
||||
return accounts.create(args)
|
||||
|
||||
|
||||
@app.route("/accounts/password/tokens", methods=["POST"])
|
||||
def password_tokens_route():
|
||||
if request.method == 'POST':
|
||||
return passwords.create_reset_token()
|
||||
if request.method == 'PUT':
|
||||
return passwords.update(request.get_json())
|
||||
|
||||
@app.route('/tokens', methods=['POST'])
|
||||
def tokens_post_route():
|
||||
if request.method == 'POST':
|
||||
return accounts.login(request.get_json())
|
||||
|
||||
@app.route('/tokens', methods=['DELETE'])
|
||||
@app.route("/accounts/password/tokens", methods=["PUT"])
|
||||
@use_args({"password": fields.Str(), "token": fields.Str()})
|
||||
def password_tokens_route_put(args):
|
||||
return passwords.update(args)
|
||||
|
||||
|
||||
@app.route("/accounts/password", methods=["PUT"])
|
||||
@use_args(
|
||||
{
|
||||
"currentPassword": fields.Str(required=True),
|
||||
"password": fields.Str(required=True, validate=validate.Length(min=8)),
|
||||
}
|
||||
)
|
||||
@util.auth
|
||||
def password_route_put(args):
|
||||
return passwords.update(args, user=g.user)
|
||||
|
||||
|
||||
@app.route("/tokens", methods=["POST"])
|
||||
@use_args({"email": fields.Email(required=True), "password": fields.Str(required=True)})
|
||||
def tokens_post_route(args):
|
||||
return accounts.login(args)
|
||||
|
||||
|
||||
@app.route("/tokens", methods=["DELETE"])
|
||||
@util.auth
|
||||
def tokens_delete_route():
|
||||
if request.method == 'DELETE':
|
||||
return accounts.logout(g.user)
|
||||
if request.method == "DELETE":
|
||||
return accounts.logout(g.user)
|
||||
|
||||
@app.route('/tokens/all', methods=['DELETE'])
|
||||
|
||||
@app.route("/tokens/all", methods=["DELETE"])
|
||||
@util.auth
|
||||
def tokens_all_delete_route():
|
||||
if request.method == 'DELETE':
|
||||
return accounts.logout_all(g.user)
|
||||
if request.method == "DELETE":
|
||||
return accounts.logout_all(g.user)
|
||||
|
||||
@app.route('/files', methods=['POST', 'GET'])
|
||||
|
||||
@app.route("/files", methods=["POST", "GET"])
|
||||
@util.auth
|
||||
def files_route():
|
||||
if request.method == 'POST':
|
||||
return files.create(g.user)
|
||||
if request.method == 'GET':
|
||||
return files.get(g.user)
|
||||
if request.method == "POST":
|
||||
return files.create(g.user)
|
||||
if request.method == "GET":
|
||||
return files.get(g.user)
|
||||
|
||||
@app.route('/files/<key>', methods=['PUT', 'GET', 'DELETE'])
|
||||
|
||||
@app.route("/files/<key>", methods=["PUT", "GET", "DELETE"])
|
||||
@util.auth
|
||||
def file_route(key):
|
||||
if request.method == 'PUT':
|
||||
return files.update_file(g.user, key)
|
||||
if request.method == 'GET':
|
||||
return files.get_file(g.user, key)
|
||||
if request.method == 'DELETE':
|
||||
return files.delete_file(g.user, key)
|
||||
if request.method == "PUT":
|
||||
return files.update_file(g.user, key)
|
||||
if request.method == "GET":
|
||||
return files.get_file(g.user, key)
|
||||
if request.method == "DELETE":
|
||||
return files.delete_file(g.user, key)
|
||||
|
@ -3,4 +3,5 @@ export FLASK_DEBUG="true"
|
||||
export FLASK_RUN_PORT="9500"
|
||||
export MONGO_URL="mongodb://localhost"
|
||||
export MONGO_DATABASE="dotty"
|
||||
export JWT_SECRET="devsecret"
|
||||
export JWT_SECRET="devsecret"
|
||||
export JWT_PASSWORD_SECRET="devsecret"
|
||||
|
114
api/files.py
114
api/files.py
@ -1,57 +1,85 @@
|
||||
import os, datetime
|
||||
import datetime
|
||||
from flask import request, jsonify, Response
|
||||
from util import database
|
||||
|
||||
max_size = 512 * 1024
|
||||
|
||||
|
||||
def create(user):
|
||||
default_path = request.headers.get('Default-Path')
|
||||
key = request.headers.get('Key')
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({'key': key, 'user': str(user['_id'])})
|
||||
if existing:
|
||||
return jsonify({'success': False, 'message': 'A key with this name already exists'}), 400
|
||||
data = request.get_data()
|
||||
if len(data) > max_size:
|
||||
return jsonify({'success': False, 'message': 'File is too large'}), 400
|
||||
if not key or not default_path or not data:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
now = datetime.datetime.utcnow()
|
||||
db.configs.insert_one({'key': key, 'defaultPath': default_path, 'createdAt': now, 'updatedAt': now, 'object': data, 'user': str(user['_id'])})
|
||||
return jsonify({'success': True}), 200
|
||||
default_path = request.headers.get("Default-Path")
|
||||
key = request.headers.get("Key")
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({"key": key, "user": str(user["_id"])})
|
||||
if existing:
|
||||
return jsonify(
|
||||
{"success": False, "message": "A key with this name already exists"}
|
||||
), 400
|
||||
data = request.get_data()
|
||||
if len(data) > max_size:
|
||||
return jsonify({"success": False, "message": "File is too large"}), 400
|
||||
if not key or not default_path or not data:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
now = datetime.datetime.utcnow()
|
||||
db.configs.insert_one(
|
||||
{
|
||||
"key": key,
|
||||
"defaultPath": default_path,
|
||||
"createdAt": now,
|
||||
"updatedAt": now,
|
||||
"object": data,
|
||||
"user": str(user["_id"]),
|
||||
}
|
||||
)
|
||||
return jsonify({"success": True}), 200
|
||||
|
||||
|
||||
def get(user):
|
||||
db = database.get_db()
|
||||
files_list = list(db.configs.find({'user': str(user['_id'])}, {'_id': 0, 'key': 1, 'defaultPath': 1}))
|
||||
return jsonify(files_list), 200
|
||||
db = database.get_db()
|
||||
files_list = list(
|
||||
db.configs.find(
|
||||
{"user": str(user["_id"])}, {"_id": 0, "key": 1, "defaultPath": 1}
|
||||
)
|
||||
)
|
||||
return jsonify(files_list), 200
|
||||
|
||||
|
||||
def update_file(user, key):
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({'key': key, 'user': str(user['_id'])})
|
||||
if not existing:
|
||||
return jsonify({'success': False, 'message': 'A file with this key could not be found'}), 404
|
||||
data = request.get_data()
|
||||
if len(data) > max_size:
|
||||
return jsonify({'success': False, 'message': 'File is too large'}), 400
|
||||
if not key or not data:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
now = datetime.datetime.utcnow()
|
||||
db.configs.update_one({'_id': existing['_id']}, {'$set': {'updatedAt': now, 'object': data}})
|
||||
return jsonify({'success': True}), 200
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({"key": key, "user": str(user["_id"])})
|
||||
if not existing:
|
||||
return jsonify(
|
||||
{"success": False, "message": "A file with this key could not be found"}
|
||||
), 404
|
||||
data = request.get_data()
|
||||
if len(data) > max_size:
|
||||
return jsonify({"success": False, "message": "File is too large"}), 400
|
||||
if not key or not data:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
now = datetime.datetime.utcnow()
|
||||
db.configs.update_one(
|
||||
{"_id": existing["_id"]}, {"$set": {"updatedAt": now, "object": data}}
|
||||
)
|
||||
return jsonify({"success": True}), 200
|
||||
|
||||
|
||||
def get_file(user, key):
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({'key': key, 'user': str(user['_id'])})
|
||||
if not existing:
|
||||
return jsonify({'success': False, 'message': 'The specified file could not be found'}), 404
|
||||
resp = Response(existing['object'])
|
||||
resp.headers['Default-Path'] = existing['defaultPath']
|
||||
return resp
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({"key": key, "user": str(user["_id"])})
|
||||
if not existing:
|
||||
return jsonify(
|
||||
{"success": False, "message": "The specified file could not be found"}
|
||||
), 404
|
||||
resp = Response(existing["object"])
|
||||
resp.headers["Default-Path"] = existing["defaultPath"]
|
||||
return resp
|
||||
|
||||
|
||||
def delete_file(user, key):
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({'key': key, 'user': str(user['_id'])})
|
||||
if not existing:
|
||||
return jsonify({'success': False, 'message': 'The specified file could not be found'}), 404
|
||||
db.configs.delete_one({'key': key, 'user': str(user['_id'])})
|
||||
return jsonify({'success': True}), 200
|
||||
db = database.get_db()
|
||||
existing = db.configs.find_one({"key": key, "user": str(user["_id"])})
|
||||
if not existing:
|
||||
return jsonify(
|
||||
{"success": False, "message": "The specified file could not be found"}
|
||||
), 404
|
||||
db.configs.delete_one({"key": key, "user": str(user["_id"])})
|
||||
return jsonify({"success": True}), 200
|
||||
|
4
api/lint.sh
Executable file
4
api/lint.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
ruff format .
|
||||
ruff check --fix .
|
134
api/passwords.py
134
api/passwords.py
@ -1,49 +1,99 @@
|
||||
import os, datetime, hashlib
|
||||
import jwt, bcrypt
|
||||
import os
|
||||
import datetime
|
||||
import hashlib
|
||||
import jwt
|
||||
import bcrypt
|
||||
from bson.objectid import ObjectId
|
||||
from flask import request, jsonify, Response
|
||||
from flask import request, jsonify
|
||||
from util import database, mail
|
||||
|
||||
secret = os.environ.get('JWT_PASSWORD_SECRET')
|
||||
secret = os.environ.get("JWT_PASSWORD_SECRET")
|
||||
|
||||
|
||||
def create_reset_token():
|
||||
data = request.get_data()
|
||||
if not data: return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
db = database.get_db()
|
||||
user = db.users.find_one({'email': data.decode('ascii')})
|
||||
if not user: return jsonify({'success': True})
|
||||
now = datetime.datetime.utcnow()
|
||||
payload = {
|
||||
'iat': now,
|
||||
'exp': now + datetime.timedelta(hours = 3),
|
||||
'sub': str(user['_id'])
|
||||
}
|
||||
token = jwt.encode(payload, secret, algorithm='HS256').decode("utf-8")
|
||||
db.users.update_one({'_id': user['_id']}, {'$set': {'passwordResetToken': token}})
|
||||
try:
|
||||
mail.send(user['email'], 'Password reset', f'Hi there,\n\nTo reset your password please use the following token when prompted by the dotty client:\n\n{token}\n\nThanks,\n\nDotty', 'Dotty Accounts <accounts@mail.dotty.cloud>')
|
||||
return jsonify({'success': True})
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return jsonify({'success': False, 'message': 'We were unable to send a password-reset email. Please try again later.'}), 500
|
||||
data = request.get_data()
|
||||
if not data:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
db = database.get_db()
|
||||
user = db.users.find_one({"email": data.decode("ascii")})
|
||||
if not user:
|
||||
return jsonify({"success": True})
|
||||
now = datetime.datetime.utcnow()
|
||||
payload = {
|
||||
"iat": now,
|
||||
"exp": now + datetime.timedelta(hours=3),
|
||||
"sub": str(user["_id"]),
|
||||
}
|
||||
token = jwt.encode(payload, secret, algorithm="HS256")
|
||||
db.users.update_one({"_id": user["_id"]}, {"$set": {"passwordResetToken": token}})
|
||||
try:
|
||||
mail.send(
|
||||
user["email"],
|
||||
"Password reset",
|
||||
f"Hi there,\n\nTo reset your password please use the following token when prompted by the dotty client:\n\n{token}\n\nThanks,\n\nDotty",
|
||||
"Dotty Accounts <accounts@mail.dotty.cloud>",
|
||||
)
|
||||
return jsonify({"success": True})
|
||||
except Exception:
|
||||
return jsonify(
|
||||
{
|
||||
"success": False,
|
||||
"message": "We were unable to send a password-reset email. Please try again later.",
|
||||
}
|
||||
), 500
|
||||
|
||||
def update(data):
|
||||
print(data)
|
||||
if not data:
|
||||
return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
password = data.get('password')
|
||||
token = data.get('token')
|
||||
if not password or not token: return jsonify({'success': False, 'message': 'Invalid request'}), 400
|
||||
|
||||
db = database.get_db()
|
||||
user = None
|
||||
try:
|
||||
user_id = jwt.decode(token, secret)['sub']
|
||||
user = db.users.find_one({'_id': ObjectId(user_id)})
|
||||
if not user: raise Exception
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return jsonify({'success': False, 'message': 'Unable to update password. Your token may be invalid'}), 400
|
||||
hashed_password = bcrypt.hashpw(hashlib.sha256(password.encode('utf-8')).hexdigest().encode('utf-8'), bcrypt.gensalt())
|
||||
db.users.update_one({'_id': user['_id']}, {'$set': {'password': hashed_password.decode('utf-8')}})
|
||||
return jsonify({'success': True})
|
||||
def update(data, user=None):
|
||||
if not data:
|
||||
return jsonify({"success": False, "message": "Invalid request"}), 400
|
||||
|
||||
db = database.get_db()
|
||||
current_password = data.get("currentPassword")
|
||||
password = data.get("password")
|
||||
token = data.get("token")
|
||||
if not password:
|
||||
return jsonify(
|
||||
{"success": False, "message": "You must supply a new password"}
|
||||
), 400
|
||||
if token:
|
||||
try:
|
||||
user_id = jwt.decode(token, secret, algorithms="HS256")["sub"]
|
||||
user = db.users.find_one({"_id": ObjectId(user_id)})
|
||||
if not user:
|
||||
raise Exception
|
||||
except Exception:
|
||||
return jsonify(
|
||||
{
|
||||
"success": False,
|
||||
"message": "Unable to update password. Your token may be invalid",
|
||||
}
|
||||
), 400
|
||||
elif user and current_password:
|
||||
if not bcrypt.checkpw(
|
||||
hashlib.sha256(current_password.encode("utf-8"))
|
||||
.hexdigest()
|
||||
.encode("utf-8"),
|
||||
user["password"].encode("utf-8"),
|
||||
):
|
||||
return jsonify(
|
||||
{
|
||||
"success": False,
|
||||
"message": "Unable to update password. Your current password is incorrect",
|
||||
}
|
||||
), 400
|
||||
else:
|
||||
return jsonify(
|
||||
{
|
||||
"success": False,
|
||||
"message": "You must supply a token or current password.",
|
||||
}
|
||||
), 400
|
||||
|
||||
hashed_password = bcrypt.hashpw(
|
||||
hashlib.sha256(password.encode("utf-8")).hexdigest().encode("utf-8"),
|
||||
bcrypt.gensalt(),
|
||||
)
|
||||
db.users.update_one(
|
||||
{"_id": user["_id"]}, {"$set": {"password": hashed_password.decode("utf-8")}}
|
||||
)
|
||||
return jsonify({"success": True})
|
||||
|
422
api/poetry.lock
generated
422
api/poetry.lock
generated
@ -1,33 +1,39 @@
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt"
|
||||
version = "4.0.1"
|
||||
version = "4.2.0"
|
||||
description = "Modern password hashing for your software and your servers"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"},
|
||||
{file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"},
|
||||
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"},
|
||||
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"},
|
||||
{file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"},
|
||||
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"},
|
||||
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"},
|
||||
{file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"},
|
||||
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"},
|
||||
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"},
|
||||
{file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"},
|
||||
{file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"},
|
||||
{file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"},
|
||||
{file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"},
|
||||
{file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a"},
|
||||
{file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db"},
|
||||
{file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170"},
|
||||
{file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184"},
|
||||
{file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -182,38 +188,38 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.4.2"
|
||||
version = "2.6.1"
|
||||
description = "DNS toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.8,<4.0"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "dnspython-2.4.2-py3-none-any.whl", hash = "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8"},
|
||||
{file = "dnspython-2.4.2.tar.gz", hash = "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"},
|
||||
{file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"},
|
||||
{file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dnssec = ["cryptography (>=2.6,<42.0)"]
|
||||
doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"]
|
||||
doq = ["aioquic (>=0.9.20)"]
|
||||
idna = ["idna (>=2.1,<4.0)"]
|
||||
trio = ["trio (>=0.14,<0.23)"]
|
||||
wmi = ["wmi (>=1.5.1,<2.0.0)"]
|
||||
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"]
|
||||
dnssec = ["cryptography (>=41)"]
|
||||
doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"]
|
||||
doq = ["aioquic (>=0.9.25)"]
|
||||
idna = ["idna (>=3.6)"]
|
||||
trio = ["trio (>=0.23)"]
|
||||
wmi = ["wmi (>=1.5.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "flask"
|
||||
version = "3.0.0"
|
||||
version = "3.0.3"
|
||||
description = "A simple framework for building complex web applications."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "flask-3.0.0-py3-none-any.whl", hash = "sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638"},
|
||||
{file = "flask-3.0.0.tar.gz", hash = "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58"},
|
||||
{file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"},
|
||||
{file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
blinker = ">=1.6.2"
|
||||
click = ">=8.1.3"
|
||||
importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
|
||||
itsdangerous = ">=2.1.2"
|
||||
Jinja2 = ">=3.1.2"
|
||||
Werkzeug = ">=3.0.0"
|
||||
@ -224,22 +230,23 @@ dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
version = "21.2.0"
|
||||
version = "23.0.0"
|
||||
description = "WSGI HTTP Server for UNIX"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"},
|
||||
{file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"},
|
||||
{file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"},
|
||||
{file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = "*"
|
||||
|
||||
[package.extras]
|
||||
eventlet = ["eventlet (>=0.24.1)"]
|
||||
eventlet = ["eventlet (>=0.24.1,!=0.36.0)"]
|
||||
gevent = ["gevent (>=1.4.0)"]
|
||||
setproctitle = ["setproctitle"]
|
||||
testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"]
|
||||
tornado = ["tornado (>=0.2)"]
|
||||
|
||||
[[package]]
|
||||
@ -253,25 +260,6 @@ files = [
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "6.8.0"
|
||||
description = "Read metadata from Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
|
||||
{file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
perf = ["ipython"]
|
||||
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
|
||||
|
||||
[[package]]
|
||||
name = "itsdangerous"
|
||||
version = "2.1.2"
|
||||
@ -359,6 +347,25 @@ files = [
|
||||
{file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marshmallow"
|
||||
version = "3.22.0"
|
||||
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"},
|
||||
{file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=17.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"]
|
||||
docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"]
|
||||
tests = ["pytest", "pytz", "simplejson"]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.2"
|
||||
@ -372,131 +379,111 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
description = "JSON Web Token implementation in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"},
|
||||
{file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"},
|
||||
{file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"},
|
||||
{file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
crypto = ["cryptography (>=3.4.0)"]
|
||||
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
|
||||
docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
|
||||
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pymongo"
|
||||
version = "4.5.0"
|
||||
version = "4.10.1"
|
||||
description = "Python driver for MongoDB <http://www.mongodb.org>"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pymongo-4.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d4fa1b01fa7e5b7bb8d312e3542e211b320eb7a4e3d8dc884327039d93cb9e0"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux1_i686.whl", hash = "sha256:dfcd2b9f510411de615ccedd47462dae80e82fdc09fe9ab0f0f32f11cf57eeb5"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3e33064f1984db412b34d51496f4ea785a9cff621c67de58e09fb28da6468a52"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:33faa786cc907de63f745f587e9879429b46033d7d97a7b84b37f4f8f47b9b32"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:76a262c41c1a7cbb84a3b11976578a7eb8e788c4b7bfbd15c005fb6ca88e6e50"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:0f4b125b46fe377984fbaecf2af40ed48b05a4b7676a2ff98999f2016d66b3ec"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:40d5f6e853ece9bfc01e9129b228df446f49316a4252bb1fbfae5c3c9dedebad"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:152259f0f1a60f560323aacf463a3642a65a25557683f49cfa08c8f1ecb2395a"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d64878d1659d2a5bdfd0f0a4d79bafe68653c573681495e424ab40d7b6d6d41"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1bb3a62395ffe835dbef3a1cbff48fbcce709c78bd1f52e896aee990928432b"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe48f50fb6348511a3268a893bfd4ab5f263f5ac220782449d03cd05964d1ae7"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7591a3beea6a9a4fa3080d27d193b41f631130e3ffa76b88c9ccea123f26dc59"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-win32.whl", hash = "sha256:3a7166d57dc74d679caa7743b8ecf7dc3a1235a9fd178654dddb2b2a627ae229"},
|
||||
{file = "pymongo-4.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:21b953da14549ff62ea4ae20889c71564328958cbdf880c64a92a48dda4c9c53"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ead4f19d0257a756b21ac2e0e85a37a7245ddec36d3b6008d5bfe416525967dc"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aff6279e405dc953eeb540ab061e72c03cf38119613fce183a8e94f31be608f"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4c8d6aa91d3e35016847cbe8d73106e3d1c9a4e6578d38e2c346bfe8edb3ca"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08819da7864f9b8d4a95729b2bea5fffed08b63d3b9c15b4fea47de655766cf5"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a253b765b7cbc4209f1d8ee16c7287c4268d3243070bf72d7eec5aa9dfe2a2c2"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8027c9063579083746147cf401a7072a9fb6829678076cd3deff28bb0e0f50c8"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-win32.whl", hash = "sha256:9d2346b00af524757576cc2406414562cced1d4349c92166a0ee377a2a483a80"},
|
||||
{file = "pymongo-4.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c3c3525ea8658ee1192cdddf5faf99b07ebe1eeaa61bf32821126df6d1b8072b"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e5a27f348909235a106a3903fc8e70f573d89b41d723a500869c6569a391cff7"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9a9a39b7cac81dca79fca8c2a6479ef4c7b1aab95fad7544cc0e8fd943595a2"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:496c9cbcb4951183d4503a9d7d2c1e3694aab1304262f831d5e1917e60386036"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23cc6d7eb009c688d70da186b8f362d61d5dd1a2c14a45b890bd1e91e9c451f2"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fff7d17d30b2cd45afd654b3fc117755c5d84506ed25fda386494e4e0a3416e1"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6422b6763b016f2ef2beedded0e546d6aa6ba87910f9244d86e0ac7690f75c96"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-win32.whl", hash = "sha256:77cfff95c1fafd09e940b3fdcb7b65f11442662fad611d0e69b4dd5d17a81c60"},
|
||||
{file = "pymongo-4.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:e57d859b972c75ee44ea2ef4758f12821243e99de814030f69a3decb2aa86807"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2b0176f9233a5927084c79ff80b51bd70bfd57e4f3d564f50f80238e797f0c8a"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89b3f2da57a27913d15d2a07d58482f33d0a5b28abd20b8e643ab4d625e36257"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:5caee7bd08c3d36ec54617832b44985bd70c4cbd77c5b313de6f7fce0bb34f93"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1d40ad09d9f5e719bc6f729cc6b17f31c0b055029719406bd31dde2f72fca7e7"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:076afa0a4a96ca9f77fec0e4a0d241200b3b3a1766f8d7be9a905ecf59a7416b"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:3fa3648e4f1e63ddfe53563ee111079ea3ab35c3b09cd25bc22dadc8269a495f"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:44ee985194c426ddf781fa784f31ffa29cb59657b2dba09250a4245431847d73"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b33c17d9e694b66d7e96977e9e56df19d662031483efe121a24772a44ccbbc7e"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d79ae3bb1ff041c0db56f138c88ce1dfb0209f3546d8d6e7c3f74944ecd2439"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d67225f05f6ea27c8dc57f3fa6397c96d09c42af69d46629f71e82e66d33fa4f"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41771b22dd2822540f79a877c391283d4e6368125999a5ec8beee1ce566f3f82"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a1f26bc1f5ce774d99725773901820dfdfd24e875028da4a0252a5b48dcab5c"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3236cf89d69679eaeb9119c840f5c7eb388a2110b57af6bb6baf01a1da387c18"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e1f61355c821e870fb4c17cdb318669cfbcf245a291ce5053b41140870c3e5cc"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-win32.whl", hash = "sha256:49dce6957598975d8b8d506329d2a3a6c4aee911fa4bbcf5e52ffc6897122950"},
|
||||
{file = "pymongo-4.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2227a08b091bd41df5aadee0a5037673f691e2aa000e1968b1ea2342afc6880"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:435228d3c16a375274ac8ab9c4f9aef40c5e57ddb8296e20ecec9e2461da1017"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8e559116e4128630ad3b7e788e2e5da81cbc2344dee246af44471fa650486a70"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:840eaf30ccac122df260b6005f9dfae4ac287c498ee91e3e90c56781614ca238"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b4fe46b58010115514b842c669a0ed9b6a342017b15905653a5b1724ab80917f"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:a8127437ebc196a6f5e8fddd746bd0903a400dc6b5ae35df672dd1ccc7170a2a"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:2988ef5e6b360b3ff1c6d55c53515499de5f48df31afd9f785d788cdacfbe2d3"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:e249190b018d63c901678053b4a43e797ca78b93fb6d17633e3567d4b3ec6107"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1240edc1a448d4ada4bf1a0e55550b6292420915292408e59159fd8bbdaf8f63"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6d2a56fc2354bb6378f3634402eec788a8f3facf0b3e7d468db5f2b5a78d763"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a0aade2b11dc0c326ccd429ee4134d2d47459ff68d449c6d7e01e74651bd255"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74c0da07c04d0781490b2915e7514b1adb265ef22af039a947988c331ee7455b"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3754acbd7efc7f1b529039fcffc092a15e1cf045e31f22f6c9c5950c613ec4d"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:631492573a1bef2f74f9ac0f9d84e0ce422c251644cd81207530af4aa2ee1980"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e2654d1278384cff75952682d17c718ecc1ad1d6227bb0068fd826ba47d426a5"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:168172ef7856e20ec024fe2a746bfa895c88b32720138e6438fd765ebd2b62dd"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-win32.whl", hash = "sha256:b25f7bea162b3dbec6d33c522097ef81df7c19a9300722fa6853f5b495aecb77"},
|
||||
{file = "pymongo-4.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:b520aafc6cb148bac09ccf532f52cbd31d83acf4d3e5070d84efe3c019a1adbf"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8543253adfaa0b802bfa88386db1009c6ebb7d5684d093ee4edc725007553d21"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:bc5d8c3647b8ae28e4312f1492b8f29deebd31479cd3abaa989090fb1d66db83"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:505f8519c4c782a61d94a17b0da50be639ec462128fbd10ab0a34889218fdee3"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:53f2dda54d76a98b43a410498bd12f6034b2a14b6844ca08513733b2b20b7ad8"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9c04b9560872fa9a91251030c488e0a73bce9321a70f991f830c72b3f8115d0d"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:58a63a26a1e3dc481dd3a18d6d9f8bd1d576cd1ffe0d479ba7dd38b0aeb20066"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:f076b779aa3dc179aa3ed861be063a313ed4e48ae9f6a8370a9b1295d4502111"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:1b1d7d9aabd8629a31d63cd106d56cca0e6420f38e50563278b520f385c0d86e"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37df8f6006286a5896d1cbc3efb8471ced42e3568d38e6cb00857277047b0d63"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56320c401f544d762fc35766936178fbceb1d9261cd7b24fbfbc8fb6f67aa8a5"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbd705d5f3c3d1ff2d169e418bb789ff07ab3c70d567cc6ba6b72b04b9143481"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a167081c75cf66b32f30e2f1eaee9365af935a86dbd76788169911bed9b5d5"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c42748ccc451dfcd9cef6c5447a7ab727351fd9747ad431db5ebb18a9b78a4d"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf62da7a4cdec9a4b2981fcbd5e08053edffccf20e845c0b6ec1e77eb7fab61d"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b5bbb87fa0511bd313d9a2c90294c88db837667c2bda2ea3fa7a35b59fd93b1f"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-win32.whl", hash = "sha256:465fd5b040206f8bce7016b01d7e7f79d2fcd7c2b8e41791be9632a9df1b4999"},
|
||||
{file = "pymongo-4.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:63d8019eee119df308a075b8a7bdb06d4720bf791e2b73d5ab0e7473c115d79c"},
|
||||
{file = "pymongo-4.5.0.tar.gz", hash = "sha256:681f252e43b3ef054ca9161635f81b730f4d8cadd28b3f2b2004f5a72f853982"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e699aa68c4a7dea2ab5a27067f7d3e08555f8d2c0dc6a0c8c60cfd9ff2e6a4b1"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:70645abc714f06b4ad6b72d5bf73792eaad14e3a2cfe29c62a9c81ada69d9e4b"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae2fd94c9fe048c94838badcc6e992d033cb9473eb31e5710b3707cba5e8aee2"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ded27a4a5374dae03a92e084a60cdbcecd595306555bda553b833baf3fc4868"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ecc2455e3974a6c429687b395a0bc59636f2d6aedf5785098cf4e1f180f1c71"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920fee41f7d0259f5f72c1f1eb331bc26ffbdc952846f9bd8c3b119013bb52c"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0a15665b2d6cf364f4cd114d62452ce01d71abfbd9c564ba8c74dcd7bbd6822"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-win32.whl", hash = "sha256:29e1c323c28a4584b7095378ff046815e39ff82cdb8dc4cc6dfe3acf6f9ad1f8"},
|
||||
{file = "pymongo-4.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:88dc4aa45f8744ccfb45164aedb9a4179c93567bbd98a33109d7dc400b00eb08"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:57ee6becae534e6d47848c97f6a6dff69e3cce7c70648d6049bd586764febe59"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6f437a612f4d4f7aca1812311b1e84477145e950fdafe3285b687ab8c52541f3"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a970fd3117ab40a4001c3dad333bbf3c43687d90f35287a6237149b5ccae61d"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c4d0e7cd08ef9f8fbf2d15ba281ed55604368a32752e476250724c3ce36c72e"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca6f700cff6833de4872a4e738f43123db34400173558b558ae079b5535857a4"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cec237c305fcbeef75c0bcbe9d223d1e22a6e3ba1b53b2f0b79d3d29c742b45b"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3337804ea0394a06e916add4e5fac1c89902f1b6f33936074a12505cab4ff05"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-win32.whl", hash = "sha256:778ac646ce6ac1e469664062dfe9ae1f5c9961f7790682809f5ec3b8fda29d65"},
|
||||
{file = "pymongo-4.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:9df4ab5594fdd208dcba81be815fa8a8a5d8dedaf3b346cbf8b61c7296246a7a"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fbedc4617faa0edf423621bb0b3b8707836687161210d470e69a4184be9ca011"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7bd26b2aec8ceeb95a5d948d5cc0f62b0eb6d66f3f4230705c1e3d3d2c04ec76"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb104c3c2a78d9d85571c8ac90ec4f95bca9b297c6eee5ada71fabf1129e1674"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4924355245a9c79f77b5cda2db36e0f75ece5faf9f84d16014c0a297f6d66786"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11280809e5dacaef4971113f0b4ff4696ee94cfdb720019ff4fa4f9635138252"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5d55f2a82e5eb23795f724991cac2bffbb1c0f219c0ba3bf73a835f97f1bb2e"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e974ab16a60be71a8dfad4e5afccf8dd05d41c758060f5d5bda9a758605d9a5d"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-win32.whl", hash = "sha256:544890085d9641f271d4f7a47684450ed4a7344d6b72d5968bfae32203b1bb7c"},
|
||||
{file = "pymongo-4.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:dcc07b1277e8b4bf4d7382ca133850e323b7ab048b8353af496d050671c7ac52"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:90bc6912948dfc8c363f4ead54d54a02a15a7fee6cfafb36dc450fc8962d2cb7"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:594dd721b81f301f33e843453638e02d92f63c198358e5a0fa8b8d0b1218dabc"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0783e0c8e95397c84e9cf8ab092ab1e5dd7c769aec0ef3a5838ae7173b98dea0"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fb6a72e88df46d1c1040fd32cd2d2c5e58722e5d3e31060a0393f04ad3283de"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e3a593333e20c87415420a4fb76c00b7aae49b6361d2e2205b6fece0563bf40"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72e2ace7456167c71cfeca7dcb47bd5dceda7db2231265b80fc625c5e8073186"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ad05eb9c97e4f589ed9e74a00fcaac0d443ccd14f38d1258eb4c39a35dd722b"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-win32.whl", hash = "sha256:ee4c86d8e6872a61f7888fc96577b0ea165eb3bdb0d841962b444fa36001e2bb"},
|
||||
{file = "pymongo-4.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:442ca247f53ad24870a01e80a71cd81b3f2318655fd9d66748ee2bd1b1569d9e"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23e1d62df5592518204943b507be7b457fb8a4ad95a349440406fd42db5d0923"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6131bc6568b26e7495a9f3ef2b1700566b76bbecd919f4472bfe90038a61f425"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdeba88c540c9ed0338c0b2062d9f81af42b18d6646b3e6dda05cf6edd46ada9"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15a624d752dd3c89d10deb0ef6431559b6d074703cab90a70bb849ece02adc6b"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba164e73fdade9b4614a2497321c5b7512ddf749ed508950bdecc28d8d76a2d9"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9235fa319993405ae5505bf1333366388add2e06848db7b3deee8f990b69808e"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e4a65567bd17d19f03157c7ec992c6530eafd8191a4e5ede25566792c4fe3fa2"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f1945d48fb9b8a87d515da07f37e5b2c35b364a435f534c122e92747881f4a7c"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-win32.whl", hash = "sha256:345f8d340802ebce509f49d5833cc913da40c82f2e0daf9f60149cacc9ca680f"},
|
||||
{file = "pymongo-4.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:3a70d5efdc0387ac8cd50f9a5f379648ecfc322d14ec9e1ba8ec957e5d08c372"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15b1492cc5c7cd260229590be7218261e81684b8da6d6de2660cf743445500ce"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95207503c41b97e7ecc7e596d84a61f441b4935f11aa8332828a754e7ada8c82"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb99f003c720c6d83be02c8f1a7787c22384a8ca9a4181e406174db47a048619"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2bc1ee4b1ca2c4e7e6b7a5e892126335ec8d9215bcd3ac2fe075870fefc3358"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:93a0833c10a967effcd823b4e7445ec491f0bf6da5de0ca33629c0528f42b748"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f56707497323150bd2ed5d63067f4ffce940d0549d4ea2dfae180deec7f9363"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:409ab7d6c4223e5c85881697f365239dd3ed1b58f28e4124b846d9d488c86880"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dac78a650dc0637d610905fd06b5fa6419ae9028cf4d04d6a2657bc18a66bbce"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1ec3fa88b541e0481aff3c35194c9fac96e4d57ec5d1c122376000eb28c01431"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-win32.whl", hash = "sha256:e0e961923a7b8a1c801c43552dcb8153e45afa41749d9efbd3a6d33f45489f7a"},
|
||||
{file = "pymongo-4.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:dabe8bf1ad644e6b93f3acf90ff18536d94538ca4d27e583c6db49889e98e48f"},
|
||||
{file = "pymongo-4.10.1.tar.gz", hash = "sha256:a9de02be53b6bb98efe0b9eda84ffa1ec027fcb23a2de62c4f941d9a2f2f3330"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
dnspython = ">=1.16.0,<3.0.0"
|
||||
|
||||
[package.extras]
|
||||
aws = ["pymongo-auth-aws (<2.0.0)"]
|
||||
encryption = ["certifi", "pymongo[aws]", "pymongocrypt (>=1.6.0,<2.0.0)"]
|
||||
aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"]
|
||||
docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-autobuild (>=2020.9.1)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"]
|
||||
encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.10.0,<2.0.0)"]
|
||||
gssapi = ["pykerberos", "winkerberos (>=0.5.0)"]
|
||||
ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"]
|
||||
snappy = ["python-snappy"]
|
||||
test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"]
|
||||
zstd = ["zstandard"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
version = "2.32.3"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -509,6 +496,87 @@ urllib3 = ">=1.21.1,<3"
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.6.9"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"},
|
||||
{file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"},
|
||||
{file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"},
|
||||
{file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"},
|
||||
{file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"},
|
||||
{file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"},
|
||||
{file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"},
|
||||
{file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"},
|
||||
{file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"},
|
||||
{file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"},
|
||||
{file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"},
|
||||
{file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "2.15.0"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "sentry_sdk-2.15.0-py2.py3-none-any.whl", hash = "sha256:8fb0d1a4e1a640172f31502e4503543765a1fe8a9209779134a4ac52d4677303"},
|
||||
{file = "sentry_sdk-2.15.0.tar.gz", hash = "sha256:a599e7d3400787d6f43327b973e55a087b931ba2c592a7a7afa691f8eb5e75e2"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
blinker = {version = ">=1.1", optional = true, markers = "extra == \"flask\""}
|
||||
certifi = "*"
|
||||
flask = {version = ">=0.11", optional = true, markers = "extra == \"flask\""}
|
||||
markupsafe = {version = "*", optional = true, markers = "extra == \"flask\""}
|
||||
urllib3 = ">=1.26.11"
|
||||
|
||||
[package.extras]
|
||||
aiohttp = ["aiohttp (>=3.5)"]
|
||||
anthropic = ["anthropic (>=0.16)"]
|
||||
arq = ["arq (>=0.23)"]
|
||||
asyncpg = ["asyncpg (>=0.23)"]
|
||||
beam = ["apache-beam (>=2.12)"]
|
||||
bottle = ["bottle (>=0.12.13)"]
|
||||
celery = ["celery (>=3)"]
|
||||
celery-redbeat = ["celery-redbeat (>=2)"]
|
||||
chalice = ["chalice (>=1.16.0)"]
|
||||
clickhouse-driver = ["clickhouse-driver (>=0.2.0)"]
|
||||
django = ["django (>=1.8)"]
|
||||
falcon = ["falcon (>=1.4)"]
|
||||
fastapi = ["fastapi (>=0.79.0)"]
|
||||
flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"]
|
||||
grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"]
|
||||
httpx = ["httpx (>=0.16.0)"]
|
||||
huey = ["huey (>=2)"]
|
||||
huggingface-hub = ["huggingface-hub (>=0.22)"]
|
||||
langchain = ["langchain (>=0.0.210)"]
|
||||
litestar = ["litestar (>=2.0.0)"]
|
||||
loguru = ["loguru (>=0.5)"]
|
||||
openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"]
|
||||
opentelemetry = ["opentelemetry-distro (>=0.35b0)"]
|
||||
opentelemetry-experimental = ["opentelemetry-distro"]
|
||||
pure-eval = ["asttokens", "executing", "pure-eval"]
|
||||
pymongo = ["pymongo (>=3.1)"]
|
||||
pyspark = ["pyspark (>=2.4.4)"]
|
||||
quart = ["blinker (>=1.1)", "quart (>=0.16.1)"]
|
||||
rq = ["rq (>=0.6)"]
|
||||
sanic = ["sanic (>=0.8)"]
|
||||
sqlalchemy = ["sqlalchemy (>=1.2)"]
|
||||
starlette = ["starlette (>=0.19.1)"]
|
||||
starlite = ["starlite (>=1.48)"]
|
||||
tornado = ["tornado (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.0.6"
|
||||
@ -526,6 +594,27 @@ secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "webargs"
|
||||
version = "8.6.0"
|
||||
description = "Declarative parsing and validation of HTTP request objects, with built-in support for popular web frameworks, including Flask, Django, Bottle, Tornado, Pyramid, Falcon, and aiohttp."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "webargs-8.6.0-py3-none-any.whl", hash = "sha256:83da4d7105643d0a50499b06d98a6ade1a330ce66d039eaa51f715172c704aba"},
|
||||
{file = "webargs-8.6.0.tar.gz", hash = "sha256:b8d098ab92bd74c659eca705afa31d681475f218cb15c1e57271fa2103c0547a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
marshmallow = ">=3.0.0"
|
||||
packaging = ">=17.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit (>=3.5,<4.0)", "tox", "webargs[tests]"]
|
||||
docs = ["Sphinx (==8.0.2)", "furo (==2024.8.6)", "sphinx-issues (==4.1.0)", "webargs[frameworks]"]
|
||||
frameworks = ["Django (>=2.2.0)", "Flask (>=0.12.5)", "aiohttp (>=3.0.8)", "bottle (>=0.12.13)", "falcon (>=2.0.0)", "pyramid (>=1.9.1)", "tornado (>=4.5.2)"]
|
||||
tests = ["pytest", "pytest-aiohttp (>=0.3.0)", "pytest-asyncio", "webargs[frameworks]", "webtest (==3.0.1)", "webtest-aiohttp (==2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "werkzeug"
|
||||
version = "3.0.0"
|
||||
@ -543,22 +632,7 @@ MarkupSafe = ">=2.1.1"
|
||||
[package.extras]
|
||||
watchdog = ["watchdog (>=2.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.17.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"},
|
||||
{file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "cf9ff69043142d8888762d6050e94cc19bbdfcce39425af14a189750ad4d4292"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "958a271fe7a1c368156256979dde90b40cffe79186308a61c2207ea25767fcd9"
|
||||
|
@ -5,17 +5,22 @@ description = "Dotty API"
|
||||
authors = ["Will <will@dotty.cloud>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
flask = "^3.0.0"
|
||||
bcrypt = "^4.0.1"
|
||||
pyjwt = "^2.8.0"
|
||||
pymongo = "^4.5.0"
|
||||
requests = "^2.31.0"
|
||||
dnspython = "^2.4.2"
|
||||
gunicorn = "^21.2.0"
|
||||
python = "^3.12"
|
||||
flask = "^3.0.3"
|
||||
bcrypt = "^4.2.0"
|
||||
pyjwt = "^2.9.0"
|
||||
pymongo = "^4.10.1"
|
||||
requests = "^2.32.3"
|
||||
dnspython = "^2.6.1"
|
||||
gunicorn = "^23.0.0"
|
||||
webargs = "^8.6.0"
|
||||
sentry-sdk = {extras = ["flask"], version = "^2.15.0"}
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
ruff = "^0.6.9"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
||||
|
@ -3,8 +3,9 @@ from pymongo import MongoClient
|
||||
|
||||
db = None
|
||||
|
||||
|
||||
def get_db():
|
||||
global db
|
||||
if db is None:
|
||||
db = MongoClient(os.environ['MONGO_URL'])[os.environ['MONGO_DATABASE']]
|
||||
return db
|
||||
global db
|
||||
if db is None:
|
||||
db = MongoClient(os.environ["MONGO_URL"])[os.environ["MONGO_DATABASE"]]
|
||||
return db
|
||||
|
@ -1,14 +1,23 @@
|
||||
import os
|
||||
import requests
|
||||
|
||||
key = os.environ.get('MAILGUN_KEY')
|
||||
request_url = 'https://api.eu.mailgun.net/v3/mail.dotty.cloud/messages'
|
||||
key = os.environ.get("MAILGUN_KEY")
|
||||
request_url = "https://api.eu.mailgun.net/v3/mail.dotty.cloud/messages"
|
||||
|
||||
def send(recipient, subject, message, from_address = 'Dotty <noreply@mail.dotty.cloud>'):
|
||||
response = requests.post(request_url, auth=('api', key), data={
|
||||
'from': from_address,
|
||||
'to': recipient,
|
||||
'subject': subject,
|
||||
'text': message
|
||||
})
|
||||
response.raise_for_status()
|
||||
|
||||
def send(recipient, subject, message, from_address="Dotty <noreply@mail.dotty.cloud>"):
|
||||
if key:
|
||||
response = requests.post(
|
||||
request_url,
|
||||
auth=("api", key),
|
||||
data={
|
||||
"from": from_address,
|
||||
"to": recipient,
|
||||
"subject": subject,
|
||||
"text": message,
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
else:
|
||||
print("No mailgun key found")
|
||||
print(message)
|
||||
|
@ -1,35 +1,22 @@
|
||||
import json, datetime, re
|
||||
from flask import Flask, request, g, Response, jsonify
|
||||
from flask import request, g, jsonify
|
||||
from functools import wraps
|
||||
import accounts
|
||||
|
||||
|
||||
def auth(route_function):
|
||||
@wraps(route_function)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if 'Authorization' not in request.headers:
|
||||
return jsonify({'success': False, 'message': 'This resource requires authentication'}), 401
|
||||
g.user = accounts.get_user_context(request, request.headers['Authorization'].replace('Bearer ', ''))
|
||||
if g.user is None:
|
||||
return jsonify({'success': False, 'message': 'Invalid authorisation token'}), 401
|
||||
return route_function(*args, **kwargs)
|
||||
return decorated_function
|
||||
@wraps(route_function)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if "Authorization" not in request.headers:
|
||||
return jsonify(
|
||||
{"success": False, "message": "This resource requires authentication"}
|
||||
), 401
|
||||
g.user = accounts.get_user_context(
|
||||
request, request.headers["Authorization"].replace("Bearer ", "")
|
||||
)
|
||||
if g.user is None:
|
||||
return jsonify(
|
||||
{"success": False, "message": "Invalid authorisation token"}
|
||||
), 401
|
||||
return route_function(*args, **kwargs)
|
||||
|
||||
def maybe_auth(route_function):
|
||||
@wraps(route_function)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if 'Authorization' in request.headers:
|
||||
g.user = accounts.get_user_context(request, request.headers['Authorization'].replace('Bearer ', ''))
|
||||
else: g.user = None
|
||||
return route_function(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
class JsonEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, (datetime.datetime, datetime.date)):
|
||||
return obj.isoformat()
|
||||
elif isinstance(obj, ObjectId):
|
||||
return str(obj)
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
def jsonify(*args, **kwargs):
|
||||
return json.dumps(dict(*args, **kwargs), cls=JsonEncoder)
|
||||
return decorated_function
|
||||
|
@ -321,10 +321,11 @@ func Logout(arg string) error {
|
||||
func ChangePassword(currentPassword *string, newPassword *string) error {
|
||||
m := make(map[string]string)
|
||||
m["currentPassword"] = *currentPassword
|
||||
m["newPassword"] = *newPassword
|
||||
m["password"] = *newPassword
|
||||
data, _ := json.Marshal(m)
|
||||
conf := *config.Load()
|
||||
_, reqErr := authenticatedRequest(&conf.AccessToken, "PUT", "/accounts/password", nil, strings.NewReader(string(data)))
|
||||
headers := map[string]string{"Content-Type": "application/json"};
|
||||
_, reqErr := authenticatedRequest(&conf.AccessToken, "PUT", "/accounts/password", &headers, strings.NewReader(string(data)))
|
||||
return reqErr
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
web/.yarn/cache/fsevents-patch-3340e2eb10-8.zip
vendored
BIN
web/.yarn/cache/fsevents-patch-3340e2eb10-8.zip
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user