pinecrypt-gateway-backend/pinecrypt/server/tokens.py

99 lines
3.0 KiB
Python

import string
import pytz
import pymongo
from datetime import datetime, timedelta
from pinecrypt.server import mailer, const, errors, db
from pinecrypt.server.common import random
class TokenManager():
def consume(self, uuid):
now = datetime.utcnow().replace(tzinfo=pytz.UTC)
doc = db.tokens.find_one_and_update({
"uuid": uuid,
"created": {"$lte": now + const.CLOCK_SKEW_TOLERANCE},
"expires": {"$gte": now - const.CLOCK_SKEW_TOLERANCE},
"used": False
}, {
"$set": {
"used": now
}
}, return_document=pymongo.ReturnDocument.AFTER)
if not doc:
raise errors.TokenDoesNotExist
return doc["subject"], doc["mail"], doc["created"], doc["expires"], doc["profile"]
def issue(self, issuer, subject, subject_mail=None):
# Expand variables
subject_username = subject.name
if not subject_mail:
subject_mail = subject.mail
# Generate token
token = "".join(random.choice(string.ascii_lowercase +
string.ascii_uppercase + string.digits) for _ in range(32))
token_created = datetime.utcnow().replace(tzinfo=pytz.UTC)
token_expires = token_created + timedelta(seconds=const.TOKEN_LIFETIME)
d = {}
d["expires"] = token_expires
d["uuid"] = token
d["issuer"] = issuer.name if issuer else None
d["subject"] = subject_username
d["mail"] = subject_mail
d["used"] = False
d["profile"] = "Roadwarrior"
db.tokens.update_one({
"subject": subject_username,
"mail": subject_mail,
"used": False
}, {
"$set": d,
"$setOnInsert": {
"created": token_created,
}
}, upsert=True)
# Token lifetime in local time, to select timezone: dpkg-reconfigure tzdata
try:
with open("/etc/timezone") as fh:
token_timezone = fh.read().strip()
except EnvironmentError:
token_timezone = None
authority_name = const.AUTHORITY_NAMESPACE
protocols = ",".join(const.SERVICE_PROTOCOLS)
url = const.TOKEN_URL % locals()
context = globals()
context.update(locals())
mailer.send("token.md", to=subject_mail, **context)
return token
def list(self, expired=False, used=False):
query = {}
if not used:
query["used"] = {"$eq": False}
if not expired:
query["expires"] = {"$gte": datetime.utcnow().replace(tzinfo=pytz.UTC)}
def g():
for token in db.tokens.find(query).sort("expires", -1):
token.pop("_id")
token["uuid"] = token["uuid"][0:8]
yield token
return tuple(g())
def purge(self, all=False):
query = {}
if not all:
query["expires"] = {"$lt": datetime.utcnow().replace(tzinfo=pytz.UTC)}
return db.tokens.remove(query)