mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 05:54:19 +01:00
Add a description field to api tokens and make api tokens start with a 'ctfd_' prefix (#2337)
* Add a description field for API tokens * API tokens now start with a `ctfd_` prefix to make them easier to identify * Closes #2184
This commit is contained in:
@@ -85,11 +85,14 @@ class TokenList(Resource):
|
|||||||
def post(self):
|
def post(self):
|
||||||
req = request.get_json()
|
req = request.get_json()
|
||||||
expiration = req.get("expiration")
|
expiration = req.get("expiration")
|
||||||
|
description = req.get("description")
|
||||||
if expiration:
|
if expiration:
|
||||||
expiration = datetime.datetime.strptime(expiration, "%Y-%m-%d")
|
expiration = datetime.datetime.strptime(expiration, "%Y-%m-%d")
|
||||||
|
|
||||||
user = get_current_user()
|
user = get_current_user()
|
||||||
token = generate_user_token(user, expiration=expiration)
|
token = generate_user_token(
|
||||||
|
user, expiration=expiration, description=description
|
||||||
|
)
|
||||||
|
|
||||||
# Explicitly use admin view so that user's can see the value of their token
|
# Explicitly use admin view so that user's can see the value of their token
|
||||||
schema = TokenSchema(view="admin")
|
schema = TokenSchema(view="admin")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from flask import session
|
from flask import session
|
||||||
from flask_babel import lazy_gettext as _l
|
from flask_babel import lazy_gettext as _l
|
||||||
from wtforms import PasswordField, SelectField, StringField
|
from wtforms import PasswordField, SelectField, StringField, TextAreaField
|
||||||
from wtforms.fields.html5 import DateField, URLField
|
from wtforms.fields.html5 import DateField, URLField
|
||||||
|
|
||||||
from CTFd.constants.languages import SELECT_LANGUAGE_LIST
|
from CTFd.constants.languages import SELECT_LANGUAGE_LIST
|
||||||
@@ -50,4 +50,5 @@ def SettingsForm(*args, **kwargs):
|
|||||||
|
|
||||||
class TokensForm(BaseForm):
|
class TokensForm(BaseForm):
|
||||||
expiration = DateField(_l("Expiration"))
|
expiration = DateField(_l("Expiration"))
|
||||||
|
description = TextAreaField("Usage Description")
|
||||||
submit = SubmitField(_l("Generate"))
|
submit = SubmitField(_l("Generate"))
|
||||||
|
|||||||
@@ -916,6 +916,7 @@ class Tokens(db.Model):
|
|||||||
db.DateTime,
|
db.DateTime,
|
||||||
default=lambda: datetime.datetime.utcnow() + datetime.timedelta(days=30),
|
default=lambda: datetime.datetime.utcnow() + datetime.timedelta(days=30),
|
||||||
)
|
)
|
||||||
|
description = db.Column(db.Text)
|
||||||
value = db.Column(db.String(128), unique=True)
|
value = db.Column(db.String(128), unique=True)
|
||||||
|
|
||||||
user = db.relationship("Users", foreign_keys="Tokens.user_id", lazy="select")
|
user = db.relationship("Users", foreign_keys="Tokens.user_id", lazy="select")
|
||||||
|
|||||||
@@ -9,8 +9,16 @@ class TokenSchema(ma.ModelSchema):
|
|||||||
dump_only = ("id", "expiration", "type")
|
dump_only = ("id", "expiration", "type")
|
||||||
|
|
||||||
views = {
|
views = {
|
||||||
"admin": ["id", "type", "user_id", "created", "expiration", "value"],
|
"admin": [
|
||||||
"user": ["id", "type", "created", "expiration"],
|
"id",
|
||||||
|
"type",
|
||||||
|
"user_id",
|
||||||
|
"created",
|
||||||
|
"expiration",
|
||||||
|
"description",
|
||||||
|
"value",
|
||||||
|
],
|
||||||
|
"user": ["id", "type", "created", "expiration", "description"],
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, view=None, *args, **kwargs):
|
def __init__(self, view=None, *args, **kwargs):
|
||||||
|
|||||||
@@ -81,7 +81,10 @@
|
|||||||
<b>{{ form.expiration.label }}</b>
|
<b>{{ form.expiration.label }}</b>
|
||||||
{{ form.expiration(class="form-control") }}
|
{{ form.expiration(class="form-control") }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<b>{{ form.description.label }}</b>
|
||||||
|
{{ form.description(class="form-control", rows="3") }}
|
||||||
|
</div>
|
||||||
<div class="form-group text-right">
|
<div class="form-group text-right">
|
||||||
{{ form.submit(class="btn btn-md btn-primary btn-outlined") }}
|
{{ form.submit(class="btn btn-md btn-primary btn-outlined") }}
|
||||||
</div>
|
</div>
|
||||||
@@ -96,6 +99,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><b>Created</b></td>
|
<td class="text-center"><b>Created</b></td>
|
||||||
<td class="text-center"><b>Expiration</b></td>
|
<td class="text-center"><b>Expiration</b></td>
|
||||||
|
<td class="text-center"><b>Description</b></td>
|
||||||
<td class="text-center"><b>Delete</b></td>
|
<td class="text-center"><b>Delete</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -104,6 +108,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><span data-time="{{ token.created | isoformat }}"></span></td>
|
<td><span data-time="{{ token.created | isoformat }}"></span></td>
|
||||||
<td><span data-time="{{ token.expiration | isoformat }}"></span></td>
|
<td><span data-time="{{ token.expiration | isoformat }}"></span></td>
|
||||||
|
<td><span>{{ token.description | default('', true) }}</span></td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span class="delete-token" role="button" data-token-id="{{ token.id }}">
|
<span class="delete-token" role="button" data-token-id="{{ token.id }}">
|
||||||
<i class="btn-fa fas fa-times"></i>
|
<i class="btn-fa fas fa-times"></i>
|
||||||
|
|||||||
@@ -34,13 +34,15 @@ def logout_user():
|
|||||||
session.clear()
|
session.clear()
|
||||||
|
|
||||||
|
|
||||||
def generate_user_token(user, expiration=None):
|
def generate_user_token(user, expiration=None, description=None):
|
||||||
temp_token = True
|
temp_token = True
|
||||||
while temp_token is not None:
|
while temp_token is not None:
|
||||||
value = hexencode(os.urandom(32))
|
value = "ctfd_" + hexencode(os.urandom(32))
|
||||||
temp_token = UserTokens.query.filter_by(value=value).first()
|
temp_token = UserTokens.query.filter_by(value=value).first()
|
||||||
|
|
||||||
token = UserTokens(user_id=user.id, expiration=expiration, value=value)
|
token = UserTokens(
|
||||||
|
user_id=user.id, expiration=expiration, description=description, value=value
|
||||||
|
)
|
||||||
db.session.add(token)
|
db.session.add(token)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return token
|
return token
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
"""Add description column to tokens table
|
||||||
|
|
||||||
|
Revision ID: 9e6f6578ca84
|
||||||
|
Revises: 0def790057c1
|
||||||
|
Create Date: 2023-06-21 23:22:34.179636
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "9e6f6578ca84"
|
||||||
|
down_revision = "0def790057c1"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column("tokens", sa.Column("description", sa.Text(), nullable=True))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column("tokens", "description")
|
||||||
Reference in New Issue
Block a user