a b/qiita_db/download_link.py
1
# -----------------------------------------------------------------------------
2
# Copyright (c) 2014--, The Qiita Development Team.
3
#
4
# Distributed under the terms of the BSD 3-clause License.
5
#
6
# The full license is in the file LICENSE, distributed with this software.
7
# -----------------------------------------------------------------------------
8
9
import qiita_db as qdb
10
11
from jose import jwt as jose_jwt
12
from datetime import datetime, timezone
13
from qiita_core.qiita_settings import qiita_config
14
15
16
class DownloadLink(qdb.base.QiitaObject):
17
    r"""
18
    A shortened url for downloading artifacts
19
    alongside a signed jwt and expiration
20
21
    Methods
22
    -------
23
    delete_expired
24
25
    See Also
26
    --------
27
    qiita_db.QiitaObject
28
    """
29
30
    _table = "download_link"
31
32
    @classmethod
33
    def create(cls, jwt):
34
        r"""Creates a new object with a new id on the storage system
35
36
        Parameters
37
        ----------
38
        jwt : Json Web Token signing the access link.
39
        This jwt will have, at a minimum, jti and exp fields
40
41
        Raises
42
        ------
43
        IncompetentQiitaDeveloperError
44
            If the jwt is improperly signed or doesn't contain a jti or exp
45
        QiitaDBDuplicateError
46
            If the jti already exists in the database
47
        """
48
49
        jwt_data = jose_jwt.decode(jwt,
50
                                   qiita_config.jwt_secret,
51
                                   algorithms='HS256')
52
        jti = jwt_data["jti"]
53
        exp = datetime.utcfromtimestamp(jwt_data["exp"] / 1000)
54
55
        with qdb.sql_connection.TRN:
56
            if cls.exists(jti):
57
                raise qdb.exceptions.QiitaDBDuplicateError(
58
                    "JTI Already Exists")
59
60
            # insert token into database
61
            sql = """INSERT INTO qiita.{0} (jti, jwt, exp)
62
            VALUES (%s, %s, %s) RETURNING jti""".format(cls._table)
63
            qdb.sql_connection.TRN.add(sql, [jti, jwt, exp])
64
            qdb.sql_connection.TRN.execute()
65
66
    @classmethod
67
    def delete(cls, jti):
68
        r"""Deletes the link with specified jti from the storage system
69
70
        Parameters
71
        ----------
72
        jti : object
73
            The jwt token identifier
74
        """
75
        sql = """DELETE FROM qiita.{0} WHERE jti=%s""".format(cls._table)
76
        qdb.sql_connection.perform_as_transaction(sql, [jti])
77
78
    @classmethod
79
    def exists(cls, jti):
80
        r"""Checks if a link with specified jti exists
81
82
        Returns
83
        -------
84
        bool
85
            True if link exists else false
86
        """
87
88
        with qdb.sql_connection.TRN:
89
            sql = """SELECT COUNT(jti) FROM qiita.{0}
90
                     WHERE jti=%s""".format(cls._table)
91
            qdb.sql_connection.TRN.add(sql, [jti])
92
            return qdb.sql_connection.TRN.execute_fetchlast() == 1
93
94
    @classmethod
95
    def delete_expired(cls):
96
        r"""Deletes all expired download links"""
97
        now = datetime.now(timezone.utc)
98
99
        sql = """DELETE FROM qiita.{0} WHERE exp<%s""".format(cls._table)
100
        qdb.sql_connection.perform_as_transaction(sql, [now])
101
102
    @classmethod
103
    def get(cls, jti):
104
        r"""Retrieves a jwt by its jti
105
106
        Returns
107
        -------
108
        str
109
            A JSON web token
110
111
        """
112
113
        with qdb.sql_connection.TRN:
114
            sql = """SELECT jwt FROM qiita.{0}
115
                     WHERE jti=%s""".format(cls._table)
116
            qdb.sql_connection.TRN.add(sql, [jti])
117
            return qdb.sql_connection.TRN.execute_fetchlast()