Add multi-domain support for urls and rename url "shortening" to url "shrinking"

This commit is contained in:
Alice Gaudon 2020-07-06 14:52:38 +02:00
parent d3909c0371
commit 095e68b27e
13 changed files with 75 additions and 31 deletions

View File

@ -2,7 +2,7 @@
"bundles": { "bundles": {
"app": "js/app.js", "app": "js/app.js",
"fm": "js/fm.js", "fm": "js/fm.js",
"url-shortener": "js/url-shortener.js", "url-shrinker": "js/url-shrinker.js",
"layout": "sass/layout.scss", "layout": "sass/layout.scss",
"error": "sass/error.scss", "error": "sass/error.scss",
"logo": "img/logo.svg", "logo": "img/logo.svg",

View File

@ -1,5 +1,5 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('url-shortener-form'); const form = document.getElementById('url-shrink-form');
if (!form) return; if (!form) return;
const autogenUrlCheckbox = document.getElementById('field-autogen_url'); const autogenUrlCheckbox = document.getElementById('field-autogen_url');

View File

@ -33,4 +33,10 @@ export default Object.assign(require("wms-core/config/default").default, {
from: 'contact@ily.li', from: 'contact@ily.li',
from_name: 'ily.li', from_name: 'ily.li',
}, },
allowed_url_domains: [
'localhost:4893',
'127.0.0.1:4893',
],
default_url_domain_for_files: 0,
default_url_domain_for_urls: 1,
}); });

View File

@ -21,4 +21,10 @@ export default Object.assign(require("wms-core/config/production").default, {
secure: true, secure: true,
allow_invalid_tls: false allow_invalid_tls: false
}, },
allowed_url_domains: [
'ily.li',
'gris.li',
],
default_url_domain_for_files: 0,
default_url_domain_for_urls: 1,
}); });

View File

@ -27,9 +27,12 @@ export default class FileController extends Controller {
} }
protected async getFileUploader(req: Request, res: Response): Promise<void> { protected async getFileUploader(req: Request, res: Response): Promise<void> {
const allowedDomains = config.get<string[]>('allowed_url_domains');
res.render('file-upload', { res.render('file-upload', {
max_upload_size: config.get<string>('max_upload_size'), max_upload_size: config.get<string>('max_upload_size'),
auth_tokens: await AuthToken.select().where('user_id', req.models.user!.id!), auth_tokens: await AuthToken.select().where('user_id', req.models.user!.id!),
allowed_domains: allowedDomains,
default_domain: allowedDomains[config.get<number>('default_url_domain_for_files')],
}); });
} }
@ -108,13 +111,15 @@ export default class FileController extends Controller {
await file.save(); await file.save();
fs.renameSync(upload.path, file.storage_path); fs.renameSync(upload.path, file.storage_path);
const domain = req.body.url_domain || config.get<string[]>('allowed_url_domains')[config.get<number>('default_url_domain_for_files')];
res.format({ res.format({
json: () => res.json({ json: () => res.json({
url: file.getURL(), url: file.getURL(domain),
}), }),
text: () => res.send(file.getURL()), text: () => res.send(file.getURL(domain)),
html: () => { html: () => {
req.flash('success', 'Upload success!'); req.flash('success', 'Upload success!');
req.flash('url', file.getURL(domain));
res.redirectBack('/'); res.redirectBack('/');
}, },
}); });

View File

@ -4,12 +4,13 @@ import URLRedirect from "../models/URLRedirect";
import {REQUIRE_AUTH_MIDDLEWARE, REQUIRE_REQUEST_AUTH_MIDDLEWARE} from "wms-core/auth/AuthComponent"; import {REQUIRE_AUTH_MIDDLEWARE, REQUIRE_REQUEST_AUTH_MIDDLEWARE} from "wms-core/auth/AuthComponent";
import generateSlug from "../SlugGenerator"; import generateSlug from "../SlugGenerator";
import {BadRequestError} from "wms-core/HttpError"; import {BadRequestError} from "wms-core/HttpError";
import config from "config";
export default class URLRedirectController extends Controller { export default class URLRedirectController extends Controller {
routes(): void { routes(): void {
this.get('/url/shorten', this.getURLShortener, 'url-shortener', REQUIRE_AUTH_MIDDLEWARE); this.get('/url/shrink', this.getURLShrinker, 'url-shrinker', REQUIRE_AUTH_MIDDLEWARE);
this.get('/url/shorten/script', this.downloadLinuxScript, 'url-linux-script'); this.get('/url/shrink/script', this.downloadLinuxScript, 'url-linux-script');
this.post('/url/shorten', this.addURLFrontend, 'shorten-url', REQUIRE_AUTH_MIDDLEWARE); this.post('/url/shrink', this.addURLFrontend, 'shrink-url', REQUIRE_AUTH_MIDDLEWARE);
this.get('/urls/:page([0-9]+)?', this.getURLRedirectManager, 'url-manager', REQUIRE_AUTH_MIDDLEWARE); this.get('/urls/:page([0-9]+)?', this.getURLRedirectManager, 'url-manager', REQUIRE_AUTH_MIDDLEWARE);
this.post('/', this.addURL, 'post-url', REQUIRE_REQUEST_AUTH_MIDDLEWARE); this.post('/', this.addURL, 'post-url', REQUIRE_REQUEST_AUTH_MIDDLEWARE);
@ -18,12 +19,16 @@ export default class URLRedirectController extends Controller {
this.put('/:slug', this.addURL, 'put-url', REQUIRE_REQUEST_AUTH_MIDDLEWARE); this.put('/:slug', this.addURL, 'put-url', REQUIRE_REQUEST_AUTH_MIDDLEWARE);
} }
protected async getURLShortener(req: Request, res: Response): Promise<void> { protected async getURLShrinker(req: Request, res: Response): Promise<void> {
res.render('url-shortener'); const allowedDomains = config.get<string[]>('allowed_url_domains');
res.render('url-shrinker', {
allowed_domains: allowedDomains,
default_domain: allowedDomains[config.get<number>('default_url_domain_for_urls')],
});
} }
protected async downloadLinuxScript(req: Request, res: Response): Promise<void> { protected async downloadLinuxScript(req: Request, res: Response): Promise<void> {
res.download('assets/files/shorten_url.sh', 'shorten_url.sh'); res.download('assets/files/shrink_url.sh', 'shrink_url.sh');
} }
protected async getURLRedirectManager(req: Request, res: Response): Promise<void> { protected async getURLRedirectManager(req: Request, res: Response): Promise<void> {
@ -67,14 +72,15 @@ export default class URLRedirectController extends Controller {
await urlRedirect.save(); await urlRedirect.save();
const domain = req.body.url_domain || config.get<string[]>('allowed_url_domains')[config.get<number>('default_url_domain_for_urls')];
res.format({ res.format({
json: () => res.json({ json: () => res.json({
url: urlRedirect.getURL(), url: urlRedirect.getURL(domain),
}), }),
text: () => res.send(urlRedirect.getURL()), text: () => res.send(urlRedirect.getURL(domain)),
html: () => { html: () => {
req.flash('success', 'URL shortened successfully!'); req.flash('success', 'URL shrunk successfully!');
req.flash('url', urlRedirect.getURL()); req.flash('url', urlRedirect.getURL(domain));
res.redirectBack('/'); res.redirectBack('/');
}, },
}); });

View File

@ -39,8 +39,8 @@ export default class FileModel extends Model {
this.addProperty('ttl', new Validator().defined().min(0).max(4294967295)); this.addProperty('ttl', new Validator().defined().min(0).max(4294967295));
} }
public getURL(): string { public getURL(domain: string = config.get<string>('base_url')): string {
return config.get<string>('base_url') + Controller.route('get-file', { return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-file', {
slug: this.slug, slug: this.slug,
}); });
} }

View File

@ -35,8 +35,8 @@ export default class URLRedirect extends Model {
this.addProperty('created_at', new Validator()); this.addProperty('created_at', new Validator());
} }
public getURL(): string { public getURL(domain: string = config.get<string>('base_url')): string {
return config.get<string>('base_url') + Controller.route('get-url', { return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-url', {
slug: this.slug, slug: this.slug,
}); });
} }

View File

@ -22,7 +22,7 @@
<td><a href="{{ route('file-linux-script') }}">Download</a></td> <td><a href="{{ route('file-linux-script') }}">Download</a></td>
</tr> </tr>
<tr> <tr>
<td>shorten_url.sh</td> <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> </tr>
</tbody> </tbody>
@ -32,8 +32,8 @@
<p>Examples:</p> <p>Examples:</p>
<pre>upload_file.sh path/to/file</pre> <pre>upload_file.sh path/to/file</pre>
<pre>upload_file.sh path/to/file my_very_important_file.png</pre> <pre>upload_file.sh path/to/file my_very_important_file.png</pre>
<pre>shorten_url.sh https://gitlab.com/ArisuOngaku/ilyli</pre> <pre>shrink_url.sh https://gitlab.com/ArisuOngaku/ilyli</pre>
<pre>shorten_url.sh https://gitlab.com/ArisuOngaku/ilyli repo</pre> <pre>shrink_url.sh https://gitlab.com/ArisuOngaku/ilyli repo</pre>
</section> </section>
<hr> <hr>
@ -81,9 +81,15 @@
<td>No</td> <td>No</td>
<td>0 (never delete), 30 (delete after 30s)</td> <td>0 (never delete), 30 (delete after 30s)</td>
</tr> </tr>
<tr>
<td>url_domain</td>
<td>Choose domain name</td>
<td>No</td>
<td>{{ allowed_domains.join('|') }}</td>
</tr>
<tr> <tr>
<th colspan="4">URL shorten</th> <th colspan="4">URL shrink</th>
</tr> </tr>
<tr> <tr>
<td>type</td> <td>type</td>
@ -97,6 +103,12 @@
<td>Yes</td> <td>Yes</td>
<td>A valid URL starting with https:// or http://</td> <td>A valid URL starting with https:// or http://</td>
</tr> </tr>
<tr>
<td>url_domain</td>
<td>Choose domain name</td>
<td>No</td>
<td>{{ allowed_domains.join('|') }}</td>
</tr>
</tbody> </tbody>
</table> </table>
<p>For examples with curl, please download and review the scripts above.</p> <p>For examples with curl, please download and review the scripts above.</p>

View File

@ -21,7 +21,7 @@
{{ macros.field(_locals, 'number', 'expire_after_days', '30', 'How many days to delete this file after', null, validation_attributes='max="1825"') }} {{ macros.field(_locals, 'number', 'expire_after_days', '30', 'How many days to delete this file after', null, validation_attributes='max="1825"') }}
{{ macros.field(_locals, 'checkbox', 'never_expire', '', 'Never delete this file') }} {{ macros.field(_locals, 'checkbox', 'never_expire', '', 'Never delete this file') }}
{{ macros.field(_locals, 'text', 'slug', '', 'Custom url slug', 'Example: beautiful_image.jpg sets url to https://ily.li/beautiful_image.jpg', validation_attributes='disabled') }} {{ macros.field(_locals, 'text', 'slug', '', 'Custom url slug', 'Example: beautiful_image.jpg sets url to https://'+default_domain+'/beautiful_image.jpg', validation_attributes='disabled') }}
{{ macros.field(_locals, 'checkbox', 'autogen_url', '', 'Generate url automatically', null, validation_attributes='checked') }} {{ macros.field(_locals, 'checkbox', 'autogen_url', '', 'Generate url automatically', null, validation_attributes='checked') }}
{{ macros.csrf(getCSRFToken) }} {{ macros.csrf(getCSRFToken) }}
@ -40,6 +40,15 @@
<div class="content"></div> <div class="content"></div>
<button class="copy-button"><i data-feather="copy"></i></button> <button class="copy-button"><i data-feather="copy"></i></button>
</div> </div>
{% set url = flash('url') %}
{% if url | length %}
<div class="copyable-text">
<div class="title">URL</div>
<div class="content">{{ url }}</div>
<button class="copy-button"><i data-feather="copy"></i></button>
</div>
{% endif %}
</section> </section>
</div> </div>

View File

@ -21,7 +21,7 @@
<li><a href="{{ route('file-manager') }}"><i data-feather="folder"></i> <span class="tip">File manager</span></a></li> <li><a href="{{ route('file-manager') }}"><i data-feather="folder"></i> <span class="tip">File manager</span></a></li>
<li><a href="{{ route('file-upload') }}"><i data-feather="upload"></i> <span class="tip">Upload file</span></a></li> <li><a href="{{ route('file-upload') }}"><i data-feather="upload"></i> <span class="tip">Upload file</span></a></li>
<li><a href="{{ route('url-manager') }}"><i data-feather="link"></i> <span class="tip">URL manager</span></a></li> <li><a href="{{ route('url-manager') }}"><i data-feather="link"></i> <span class="tip">URL manager</span></a></li>
<li><a href="{{ route('url-shortener') }}"><i data-feather="crosshair"></i> <span class="tip">Shorten URL</span></a></li> <li><a href="{{ route('url-shrinker') }}"><i data-feather="crosshair"></i> <span class="tip">Shrink URL</span></a></li>
{% if user.is_admin %} {% if user.is_admin %}
<li><a href="{{ route('backend') }}"><i data-feather="settings"></i> <span class="tip">Backend</span></a></li> <li><a href="{{ route('backend') }}"><i data-feather="settings"></i> <span class="tip">Backend</span></a></li>
{% endif %} {% endif %}

View File

@ -1,28 +1,28 @@
{% extends 'layouts/base.njk' %} {% extends 'layouts/base.njk' %}
{% set title = app.name + ' - URL shortener' %} {% set title = app.name + ' - URL shrinker' %}
{% block scripts %} {% block scripts %}
<script src="/js/url-shortener.js"></script> <script src="/js/url-shrinker.js"></script>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<h1>Shorten URLs</h1> <h1>Shrink URLs</h1>
<p>(no phishing allowed)</p> <p>(no phishing allowed)</p>
<div class="container"> <div class="container">
<section class="panel"> <section class="panel">
<h2>Shorten a URL</h2> <h2>Shrink a URL</h2>
<form action="{{ route('shorten-url') }}" method="POST" id="url-shortener-form"> <form action="{{ route('shrink-url') }}" method="POST" id="url-shrink-form">
{{ macros.field(_locals, 'text', 'target_url', '', 'Target URL', 'Only valid URLs starting with http:// or https://', validation_attributes='required') }} {{ macros.field(_locals, 'text', 'target_url', '', 'Target URL', 'Only valid URLs starting with http:// or https://', validation_attributes='required') }}
{{ macros.field(_locals, 'text', 'slug', '', 'Custom url slug', 'Example: bear sets url to https://ily.li/bear', validation_attributes='disabled') }} {{ macros.field(_locals, 'text', 'slug', '', 'Custom url slug', 'Example: bear sets url to https://'+default_domain+'/bear', validation_attributes='disabled') }}
{{ macros.field(_locals, 'checkbox', 'autogen_url', '', 'Generate url automatically', null, validation_attributes='checked') }} {{ macros.field(_locals, 'checkbox', 'autogen_url', '', 'Generate url automatically', null, validation_attributes='checked') }}
{{ macros.csrf(getCSRFToken) }} {{ macros.csrf(getCSRFToken) }}
<button type="submit"><i data-feather="link"></i> Shorten URL</button> <button type="submit"><i data-feather="link"></i> Shrink URL</button>
</form> </form>
{% set url = flash('url') %} {% set url = flash('url') %}