Implement API token improvements: unique names per user, 100-year expiration,...

Implement API token improvements: unique names per user, 100-year expiration, modal on creation with reload
parent edfaa11e
......@@ -49,19 +49,6 @@
{% endif %}
{% endwith %}
{% if generated_token %}
<div class="alert alert-success">
<strong>Token Generated Successfully!</strong><br>
Copy the token below. You won't be able to see it again.
</div>
<div class="token-display">
<strong>Token Name:</strong> {{ token_name }}<br>
<strong>Token:</strong>
<pre id="tokenText">{{ generated_token }}</pre>
<button class="btn copy-btn" onclick="copyToken()">Copy Token</button>
</div>
{% endif %}
<form method="post" action="/api_tokens/generate">
<div class="form-group">
<label for="token_name">Token Name</label>
......@@ -109,6 +96,30 @@
</div>
</div>
<!-- Token Generated Modal -->
{% if generated_token %}
<div id="tokenModal" class="modal" style="display: block;">
<div class="modal-content">
<div class="modal-header">
<h3>API Token Generated Successfully!</h3>
<span onclick="closeTokenModal()" style="cursor: pointer; font-size: 1.5rem;">&times;</span>
</div>
<div class="modal-body">
<p><strong>Token Name:</strong> {{ token_name }}</p>
<p><strong>Token:</strong></p>
<div class="token-display" style="margin: 1rem 0;">
<pre id="modalTokenText">{{ generated_token }}</pre>
<button class="btn copy-btn" onclick="copyTokenFromModal()">Copy Token</button>
</div>
<p style="color: #dc2626; font-weight: 500;">Copy this token now. You won't be able to see it again!</p>
</div>
<div class="modal-footer">
<button onclick="closeTokenModal()" class="btn">Close</button>
</div>
</div>
</div>
{% endif %}
<!-- Delete Confirmation Modal -->
<div id="deleteModal" class="modal">
<div class="modal-content">
......@@ -155,12 +166,37 @@
document.getElementById('deleteModal').style.display = 'none';
}
function closeTokenModal() {
document.getElementById('tokenModal').style.display = 'none';
location.reload(); // Reload the page
}
function copyTokenFromModal() {
const tokenText = document.getElementById('modalTokenText');
navigator.clipboard.writeText(tokenText.textContent).then(function() {
alert('Token copied to clipboard!');
}, function(err) {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = tokenText.textContent;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
alert('Token copied to clipboard!');
});
}
// Close modal when clicking outside
window.onclick = function(event) {
const modal = document.getElementById('deleteModal');
if (event.target == modal) {
const deleteModal = document.getElementById('deleteModal');
if (deleteModal && event.target == deleteModal) {
closeDeleteModal();
}
const tokenModal = document.getElementById('tokenModal');
if (tokenModal && event.target == tokenModal) {
closeTokenModal();
}
// Close user dropdown
const dropdown = document.getElementById('userDropdown');
const icon = document.querySelector('.user-icon');
......
......@@ -1099,7 +1099,7 @@ def create_user_api_token(user_id: int, name: str) -> str:
'user_id': user_id,
'token_id': secrets.token_hex(16),
'iat': int(time.time()),
'exp': int(time.time()) + (365 * 24 * 60 * 60) # 1 year expiration
'exp': int(time.time()) + (100 * 365 * 24 * 60 * 60) # 100 years expiration
}
# Use a simple secret key (in production, use environment variable)
......
......@@ -386,10 +386,19 @@ def generate_api_token():
flash('Token name is required', 'error')
return redirect(url_for('api_tokens'))
# Check if token name already exists for this user
from .database import get_user_api_tokens
existing_tokens = get_user_api_tokens(user['id'])
if any(t.get('name') == token_name for t in existing_tokens):
flash('A token with this name already exists. Please choose a different name.', 'error')
return redirect(url_for('api_tokens'))
from .database import create_user_api_token
token = create_user_api_token(user['id'], token_name)
flash('API token generated successfully!', 'success')
return render_template('api_tokens.html', user=user, user_tokens=[], generated_token=token, token_name=token_name)
# Return with modal data instead of flash
from .database import get_user_api_tokens
user_tokens = get_user_api_tokens(user['id'])
return render_template('api_tokens.html', user=user, user_tokens=user_tokens, generated_token=token, token_name=token_name, show_modal=True, active_page='api_tokens')
@app.route('/api_tokens/delete/<int:token_id>', methods=['POST'])
@login_required
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment