chore(front): convert auth-tokens to svelte

This commit is contained in:
Alice Gaudon 2022-03-06 13:14:19 +01:00
parent 3abd692ce3
commit c54a201e98
3 changed files with 77 additions and 36 deletions

View File

@ -1,22 +1,31 @@
{% extends 'layouts' %}
<script lang="ts">
import {locals} from "../ts/stores.js";
import {route} from "../../common/Routing.js";
import {Time} from "../../common/Time.js";
import BaseTemplate from "./templates/BaseTemplate.svelte";
import Form from "./utils/Form.svelte";
import Icon from "./utils/Icon.svelte";
import CopyableText from "./components/CopyableText.svelte";
import Pagination from "./components/Pagination.svelte";
</script>
{% set title = app.name + ' - Auth tokens' %}
<BaseTemplate title="{$locals.app.name} - Auth tokens" description="Upload files directly from your desktop." noH1>
<h1>Auth tokens</h1>
{% block body %}
<div class="container">
<section class="panel">
<h2><i data-feather="key"></i> Auth tokens</h2>
<form action="{{ route('generate-token') }}" method="POST">
{{ macros.csrf(getCsrfToken) }}
<h2>
<Icon name="key"/>
Auth tokens
</h2>
<Form action="{route('generate-token')}" submitText="Generate a new token" submitIcon="plus"/>
<button type="submit"><i data-feather="plus"></i> Generate a new token</button>
</form>
<Pagination pagination={$locals.pagination} routeName="auth-tokens" contextSize={3}/>
<table class="data-table">
<thead>
<tr>
<th>#</th>
<th class="table-col-grow">Secret</th>
<th class="col-grow">Secret</th>
<th>Created at</th>
<th>Last used at</th>
<th>Actions</th>
@ -24,40 +33,52 @@
</thead>
<tbody>
{% for token in auth_tokens %}
{#each $locals.auth_tokens as token}
<tr>
<td>{{ token.id }}</td>
<td>{token.id}</td>
<td>
<div class="copyable-text">
<div class="content">{{ token.secret }}</div>
<button class="copy-button"><i data-feather="copy"></i></button>
</div>
<CopyableText content="{token.secret}"/>
</td>
<td>
<time datetime="{token.created_at}" title="{token.created_at}">
{Time.humanizeTimeSince(new Date(token.created_at), true)} ago
</time>
</td>
<td>
{#if token.used_at}
<time datetime="{token.used_at}" title="{token.used_at}">
{Time.humanizeTimeSince(new Date(token.used_at), true)} ago
</time>
{:else}
Never
{/if}
</td>
<td>{{ token.created_at.toISOString() }}</td>
<td>{{ token.used_at.toISOString() }}</td>
<td class="actions">
<form action="{{ route('revoke-token', token.id) }}" method="POST">
<button class="button danger"><i data-feather="trash"></i> <span class="tip">Revoke</span></button>
{{ macros.csrf(getCsrfToken) }}
</form>
<Form action="{route('revoke-token', token.id)}" submitText="Revoke" submitIcon="trash"
submitClass="danger"/>
</td>
</tr>
{% endfor %}
{/each}
</tbody>
</table>
<Pagination pagination={$locals.pagination} routeName="auth-tokens" contextSize={3}/>
</section>
<section class="panel">
<h2><i data-feather="tool"></i> Setup a desktop utility</h2>
<h2>
<Icon name="wrench"/>
Setup a desktop utility
</h2>
<p>There may be a desktop client at some point. For now, if you're an advanced user, you can setup
scripts/macros.</p>
<hr>
<section>
<h3>First alternative: sh script (native on linux)</h3>
<p>If you have the sh shell on your machine (i.e. you are on linux, git bash on windows...) and curl, you can
download and use these scripts:</p>
<p>If you have the sh shell on your machine (i.e. you are on linux, git bash on windows...) and curl, you
can download and use these scripts:</p>
<table class="data-table">
<thead>
<tr>
@ -68,11 +89,11 @@
<tbody>
<tr>
<td>upload_file.sh</td>
<td><a href="{{ route('file-linux-script') }}">Download</a></td>
<td><a href="{route('file-linux-script')}">Download</a></td>
</tr>
<tr>
<td>shrink_url.sh</td>
<td><a href="{{ route('url-linux-script') }}">Download</a></td>
<td><a href="{route('url-linux-script')}">Download</a></td>
</tr>
</tbody>
</table>
@ -134,7 +155,7 @@
<td>url_domain</td>
<td>Choose domain name</td>
<td>No</td>
<td>{{ allowed_domains.join('|') }}</td>
<td>{$locals.allowed_domains.join('|')}</td>
</tr>
<tr>
@ -156,12 +177,11 @@
<td>url_domain</td>
<td>Choose domain name</td>
<td>No</td>
<td>{{ allowed_domains.join('|') }}</td>
<td>{$locals.allowed_domains.join('|')}</td>
</tr>
</tbody>
</table>
<p>For examples with curl, please download and review the scripts above.</p>
</section>
</section>
</div>
{% endblock %}
</BaseTemplate>

View File

@ -9,7 +9,7 @@ import AuthToken from "../models/AuthToken.js";
export default class AuthTokenController extends Controller {
public routes(): void {
this.get('/auth-tokens', this.getAuthTokens, 'auth-tokens', RequireAuthMiddleware);
this.get('/auth-tokens/:page?', this.getAuthTokens, 'auth-tokens', RequireAuthMiddleware);
this.post('/gen-auth-token', this.postGenAuthToken, 'generate-token', RequireAuthMiddleware);
this.post('/revoke-auth-token/:id', this.postRevokeAuthToken, 'revoke-token', RequireAuthMiddleware);
}
@ -17,10 +17,16 @@ export default class AuthTokenController extends Controller {
public async getAuthTokens(req: Request, res: Response): Promise<void> {
const allowedDomains = config.get<string[]>('allowed_url_domains');
const user = req.as(RequireAuthMiddleware).getUser();
const authTokens = await AuthToken.paginateForUser(req, 2, user.getOrFail('id'));
res.render('auth-tokens', {
allowed_domains: allowedDomains,
default_domain: allowedDomains[config.get<number>('default_url_domain_for_files')],
auth_tokens: await AuthToken.select().where('user_id', user.id).get(),
auth_tokens: authTokens.map(token => ({
...token,
created_at: token.created_at?.toISOString(),
used_at: token.used_at?.toISOString(),
})),
pagination: authTokens.pagination?.serialize(),
});
}

View File

@ -1,14 +1,26 @@
import {Request} from "express";
import {nanoid} from "nanoid";
import AuthProof from "swaf/auth/AuthProof";
import User from "swaf/auth/models/User";
import Model from "swaf/db/Model";
import {ModelQueryResult} from "swaf/db/ModelQuery";
export default class AuthToken extends Model implements AuthProof<User> {
public static async paginateForUser(
req: Request,
perPage: number,
user_id: number,
): Promise<ModelQueryResult<AuthToken>> {
req.params.sortBy = 'created_at';
req.params.sortDirection = 'DESC';
return await this.paginate(req, perPage, this.select().where('user_id', user_id));
}
public id?: number = undefined;
protected readonly user_id?: number = undefined;
private secret?: string = undefined;
protected created_at?: Date = undefined;
protected used_at?: Date = undefined;
public created_at?: Date = undefined;
public used_at?: Date = undefined;
protected readonly ttl?: number = undefined;
protected init(): void {
@ -23,6 +35,9 @@ export default class AuthToken extends Model implements AuthProof<User> {
}
}
/**
* TODO promote this method to AuthProof interface in swaf and call it on successful authentication
*/
public use(): void {
this.used_at = new Date();
}