chore(front): convert auth-tokens to svelte
This commit is contained in:
parent
3abd692ce3
commit
c54a201e98
@ -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>
|
@ -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(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user