added unsecure http option

This commit is contained in:
urania-dev
2024-04-11 14:44:38 +02:00
parent 5d33bbbc88
commit 270a1cae66
12 changed files with 85 additions and 112 deletions

View File

@@ -50,7 +50,7 @@
- Minor cleaning here and there
- 0.6.1
- Added export to CSV for operating user, other users and all snapps on db.
- Cleaned README and CHANGELOG
- Cleaned README and CHANGELOG
- 0.6.2
- minor clean up of changelog
- minor clean up of csv auth needed
@@ -69,3 +69,7 @@
- Provided placeholder default for better understanding of missing languages file
- Corrected README unnecessarely mounting translation folder
- Fixed overlay on Single Snapp dashboard
- 0.7.2
- Fixed typo
- Fix on custom theme

View File

@@ -16,6 +16,7 @@ COPY . /app
ENV SNAPP_VERSION=0.7.1
ENV AUTH_SECRET=lFNiU7T98/44Qlqb4hMUkVcLOpijEI7z722Kxhv4O2Y=
ENV ALLOW_UNSECURE_HTTP=false
ENV DB_HOST=100.64.0.21
ENV DB_PASS=
ENV DB_PORT=6379

View File

@@ -25,7 +25,7 @@ html.dark body {
select,
input,
button {
@apply outline-0 ring-0 border-none ;
@apply outline-0 ring-0 border-none;
}
.link {

View File

@@ -115,6 +115,7 @@ async function initializeDBIndexes() {
await check_and_set('settings:app:smtp:port', env.SMTP_PORT?.toString()?.toLowerCase());
await check_and_set('settings:app:smtp:user', env.SMTP_USER?.toString()?.toLowerCase());
await check_and_set('settings:app:smtp:from', env.SMTP_FROM?.toString()?.toLowerCase());
await check_and_set('settings:app:allow:unsecure:http', env.ALLOW_UNSECURE_HTTP?.toString()?.toLowerCase());
await check_and_set('settings:api:key:vt', env.VIRUSTOTAL_API_KEY?.toString()?.toLowerCase());
await check_and_set(
'settings:api:key:umami:website:id',

View File

@@ -30,6 +30,9 @@ export default async function shorten(
const roles = user.roles;
const allow_unsecure_http =
(await this.getSetting('settings:app:allow:unsecure:http'))?.toString().toLocaleLowerCase() ===
'true';
const global_max_urls = await this.getSetting('settings:app:limits:max:urls');
const max_urls = user?.settings?.max?.urls ?? global_max_urls;
const urls = await this.snapps.search().where('user_id').equals(user_id).returnCount();
@@ -37,13 +40,13 @@ export default async function shorten(
if (urls > max_urls && (!roles.includes('admin') || !roles.includes('superadmin')))
return new SnappError(400, { message: 'snapps:max:urls:reached' });
const regex = new RegExp(/^https:\/\/[^\s/$.?#].[^\s]*$/);
const httpRegexp = new RegExp(/^https:\/\/[^\s/$.?#].[^\s]*$/);
if (!original_url || typeof original_url !== 'string' || original_url.trim() === '')
return new SnappError(400, { message: 'snapps:original:url:unset' });
if (original_url) {
if (regex.test(original_url) === false)
if (allow_unsecure_http === false && httpRegexp.test(original_url) === false)
return new SnappError(400, { message: 'snapps:original:url:invalid' });
snapp.original_url = original_url;
}

View File

@@ -281,7 +281,7 @@ services:
image: redis/redis-stack:latest
volumes:
- /etc/localtime:/etc/localtime:ro
- /home/snapp/redis/data:rw
- /home/snapp/redis:/data:rw
networks:
- snapp-stack
environment:

View File

@@ -66,7 +66,10 @@ export async function load({ locals, depends, fetch }) {
},
whitelists: {
emails: (await db.redis.zCard(whiteEmailZList)) + (await db.redis.zCard(whiteProviderZList))
}
},
allow_unsecure_http: await db
.getSetting('settings:app:allow:unsecure:http')
.then((res) => res?.toString().toLowerCase() === 'true')
},
active_smtp,
vtapikey: vtapikey !== undefined && vtapikey !== null
@@ -118,6 +121,7 @@ export const actions = {
const signup = form.get('signup')?.toString();
const home = form.get('home')?.toString();
const limits = form.get('limits')?.toString();
const allow_unsecure_http = form.get('allowUnsecureHttp')?.toString();
if (!home || (home !== 'enabled' && home !== 'disabled'))
throw error(404, { message: 'settings:not:found' });
@@ -125,6 +129,11 @@ export const actions = {
throw error(404, { message: 'settings:not:found' });
if (!limits || (limits !== 'enabled' && limits !== 'disabled'))
throw error(404, { message: 'settings:not:found' });
if (
!allow_unsecure_http ||
(allow_unsecure_http !== 'enabled' && allow_unsecure_http !== 'disabled')
)
throw error(404, { message: 'settings:not:found' });
switch (signup) {
case 'enabled':
@@ -151,6 +160,14 @@ export const actions = {
await db.setSetting('settings:app:home:enabled', 'false');
break;
}
switch (allow_unsecure_http) {
case 'enabled':
await db.setSetting('settings:app:allow:unsecure:http', 'true');
break;
case 'disabled':
await db.setSetting('settings:app:allow:unsecure:http', 'false');
break;
}
return { status: 200, success: true, message: 'settings:app:wise:saved' };
},

View File

@@ -1,5 +1,4 @@
<script lang="ts">
import Extralarge from '../../../../../lib/ui/typography/extralarge.svelte';
import { invalidate, invalidateAll } from '$app/navigation';
import CustomToast from '$lib/ui/toaster/customToast.svelte';
import { toast } from 'svelte-sonner';
@@ -23,12 +22,13 @@
import { SlideToggle, getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
import Breadcrumbs from '$lib/ui/crumbs/breadcrumbs.svelte';
import { getLocale } from '$lib/i18n';
import { H3, ExtraLarge, Lead, Paragraph, Small, Large } from '$lib/ui/typography';
import { H3, Lead, Paragraph, Small, Large } from '$lib/ui/typography';
import type { SubmitFunction } from './$types.js';
const { t } = getLocale();
export let data, form;
let is_saving = false;
let allow_unsecure_http = data.app_settings.allow_unsecure_http;
let enable_signup = data.app_settings.signup.enabled;
let enable_limits = data.app_settings.limits.enabled;
let disable_home = !data.app_settings.home.enabled;
@@ -95,6 +95,7 @@
formData.set('home', disable_home === true ? 'disabled' : 'enabled');
formData.set('signup', enable_signup === true ? 'enabled' : 'disabled');
formData.set('limits', enable_limits === true ? 'enabled' : 'disabled');
formData.set('allowUnsecureHttp', allow_unsecure_http === true ? 'enabled' : 'disabled');
return async function ({ result }) {
await applyAction(result);
@@ -181,6 +182,12 @@
is_saving = true;
document.forms.namedItem('settings')?.requestSubmit();
}
function handle_allow_unsecure_http() {
is_saving = true;
document.forms.namedItem('settings')?.requestSubmit();
}
function handle_enable_limits() {
is_saving = true;
document.forms.namedItem('settings')?.requestSubmit();
@@ -234,7 +241,7 @@
>{$t('settings:app:wise')}
{$t('settings:app:switch')}
</Paragraph>
<label for="enable-signup" class="flex flex-col gap-1 mt-4 mb-2">
<label for="enable-signup" class="flex flex-col gap-1 mb-2">
<div class="flex w-full justify-between items-center">
<Paragraph class="font-semibold flex gap-2 items-center">
<UsersIcon class="w-4 h-4" />
@@ -255,7 +262,7 @@
</div>
<Small>{$t('settings:app:sign:up:description')}</Small>
</label>
<label for="enable-homepage" class="flex flex-col gap-1 mt-4 mb-2">
<label for="enable-homepage" class="flex flex-col gap-1 mb-2">
<div class="flex w-full justify-between items-center">
<Paragraph class="font-semibold flex gap-2 items-center">
<HomeIcon class="w-4 h-4" />
@@ -274,7 +281,28 @@
/>
</div>
</div>
<Small>{$t('settings:app:home:description')}</Small>
<Small>{@html $t('settings:app:home:description')}</Small>
</label>
<label for="allow-unsecure-http" class="flex flex-col gap-1 mb-2">
<div class="flex w-full justify-between items-center">
<Paragraph class="font-semibold flex gap-2 items-center">
<HomeIcon class="w-4 h-4" />
{$t('settings:app:allow:unsecure:http')}
</Paragraph>
<div class="flex items-center justify-end scale-[.8]">
<SlideToggle
size="sm"
id="allow-unsecure-http"
name="allow_unsecure_http"
background="bg-surface-300-600-token"
active="bg-success-300-600-token"
disabled={is_saving}
bind:checked={allow_unsecure_http}
on:change={handle_allow_unsecure_http}
/>
</div>
</div>
<Small>{@html $t('settings:app:allow:unsecure:http:description')}</Small>
</label>
</div>
</div>

View File

@@ -13,9 +13,13 @@ export async function load({ locals, parent }) {
const isAdmin = await db.admin(session.user.id);
const ALLOW_UNSECURE_HTTP =
(await db.getSetting('settings:app:allow:unsecure:http'))?.toString()?.toLowerCase() === 'true';
console.log(ALLOW_UNSECURE_HTTP)
return {
max_urls: user.settings?.max?.urls ?? data.max_urls ?? 0,
existing: await db.snapps.search().where('user_id').equal(session.user.id).returnCount(),
allow_unsecure_http: ALLOW_UNSECURE_HTTP,
isAdmin: (typeof isAdmin === 'boolean' && isAdmin) || false
};
}
@@ -43,7 +47,7 @@ export const actions: Actions = {
let expiration: number | undefined;
if (_expires) expiration = _expires === '-1' ? -1 : Math.ceil(Number(_expires) / 1000);
let newSnapp: Partial<DBSnapp> = {
id: randomUUID(),
original_url,
@@ -53,7 +57,7 @@ export const actions: Actions = {
notes,
user_id: session.user.id
};
const result = await db.shorten(newSnapp, fetch, expiration);
if (result.status !== 200) {

View File

@@ -83,6 +83,11 @@
is_invalid_url = false;
is_valid_url = false;
} else {
if (data.allow_unsecure_http) {
is_valid_url = true;
is_invalid_url = false;
return;
}
is_valid_url = httpsRegexp.test(original_url);
is_invalid_url = !is_valid_url;
}
@@ -157,7 +162,7 @@
<label for="original_url" class="flex flex-col gap-1">
<Paragraph class="font-semibold">{$t('snapps:original:url:label')}</Paragraph>
<div
class="input-group max-w-sm input-group-divider grid-cols-[auto_1fr_auto]"
class="input-group input-group-divider grid-cols-[auto_1fr_auto]"
class:variant-glass-success={is_valid_url}
class:variant-glass-error={is_invalid_url}
>
@@ -177,11 +182,13 @@
bind:value={original_url}
/>
</div>
<Small class="mt-1">{@html $t('snapps:original:url:helper')}</Small>
<Small class="mt-1"
>{#if data.allow_unsecure_http}{@html $t('snapps:original:url:helper')}{/if}</Small
>
</label>
<label for="shortcode" class="flex flex-col gap-1">
<Paragraph class="font-semibold">{$t('snapps:shortcode:label')}</Paragraph>
<div class="input-group max-w-sm input-group-divider grid-cols-[auto_1fr_auto]">
<div class="input-group input-group-divider grid-cols-[auto_1fr_auto]">
<div class="flex items-center w-10" style:padding="0" style:justify-content="center">
<LinkIcon strokeWidth="1.5" class="w-5 h-5" />
</div>
@@ -319,7 +326,7 @@
>{@html $t('snapps:sections:advanced:secret:description')}</Paragraph
>
<div
class="input-group max-w-sm h-10 mt-2 flex-grow-0input-group-divider grid-cols-[auto_1fr_auto]"
class="input-group h-10 mt-2 flex-grow-0input-group-divider grid-cols-[auto_1fr_auto]"
>
<div class="flex items-center w-10" style:padding="0" style:justify-content="center">
<KeyIcon strokeWidth="1.5" class="w-5 h-5" />

View File

@@ -1,94 +0,0 @@
/* :root [data-theme="snappTheme"] {
--theme-font-family-base: `system-ui`;
--theme-font-family-heading: `system-ui`;
--theme-font-color-base: 0 0 0;
--theme-font-color-dark: 255 255 255;
--theme-rounded-base: 0px;
--theme-rounded-container: 0px;
--theme-border-base: 1px;
--on-primary: 0 0 0;
--on-secondary: 255 255 255;
--on-tertiary: 255 255 255;
--on-success: 0 0 0;
--on-warning: 0 0 0;
--on-error: 255 255 255;
--on-surface: 255 255 255;
--color-primary-50: 249 243 225;
--color-primary-100: 246 239 215;
--color-primary-200: 244 235 205;
--color-primary-300: 238 223 175;
--color-primary-400: 225 199 115;
--color-primary-500: 212 175 55;
--color-primary-600: 191 158 50;
--color-primary-700: 159 131 41;
--color-primary-800: 127 105 33;
--color-primary-900: 104 86 27;
--color-secondary-50: 238 231 236;
--color-secondary-100: 233 222 229;
--color-secondary-200: 227 214 223;
--color-secondary-300: 210 190 203;
--color-secondary-400: 177 141 164;
--color-secondary-500: 143 92 125;
--color-secondary-600: 129 83 113;
--color-secondary-700: 107 69 94;
--color-secondary-800: 86 55 75;
--color-secondary-900: 70 45 61;
--color-tertiary-50: 222 228 233;
--color-tertiary-100: 211 218 225;
--color-tertiary-200: 201 209 218;
--color-tertiary-300: 168 182 196;
--color-tertiary-400: 102 127 151;
--color-tertiary-500: 37 72 107;
--color-tertiary-600: 33 65 96;
--color-tertiary-700: 28 54 80;
--color-tertiary-800: 22 43 64;
--color-tertiary-900: 18 35 52;
--color-success-50: 242 247 220;
--color-success-100: 238 245 208;
--color-success-200: 233 242 197;
--color-success-300: 220 235 161;
--color-success-400: 194 219 91;
--color-success-500: 168 204 21;
--color-success-600: 151 184 19;
--color-success-700: 126 153 16;
--color-success-800: 101 122 13;
--color-success-900: 82 100 10;
--color-warning-50: 248 230 222;
--color-warning-100: 245 221 211;
--color-warning-200: 243 213 200;
--color-warning-300: 236 188 167;
--color-warning-400: 221 137 101;
--color-warning-500: 207 87 35;
--color-warning-600: 186 78 32;
--color-warning-700: 155 65 26;
--color-warning-800: 124 52 21;
--color-warning-900: 101 43 17;
--color-error-50: 249 221 234;
--color-error-100: 246 209 228;
--color-error-200: 244 198 221;
--color-error-300: 238 163 200;
--color-error-400: 225 94 159;
--color-error-500: 212 25 118;
--color-error-600: 191 23 106;
--color-error-700: 159 19 89;
--color-error-800: 127 15 71;
--color-error-900: 104 12 58;
--color-surface-50: 224 225 226;
--color-surface-100: 214 215 216;
--color-surface-200: 204 206 206;
--color-surface-300: 173 176 177;
--color-surface-400: 112 116 119;
--color-surface-500: 51 57 60;
--color-surface-600: 46 51 54;
--color-surface-700: 38 43 45;
--color-surface-800: 31 34 36;
--color-surface-900: 25 28 29;
} */

View File

@@ -209,7 +209,9 @@
"settings:app:exports:all": "Export all",
"settings:app:exports:confirm:message": "This will exports all snapps in the database, and may require some time depending on the size of the database. Do you want to continue?",
"settings:app:exports:helper": "If you want to leave Snapp you can export a CSV with all your shortened-url.",
"settings:app:home:description": "Redirect users to login or dashboard instead..",
"settings:app:home:description": "Redirect users to login or dashboard instead.",
"settings:app:allow:unsecure:http": "Allow Unsecure HTTP",
"settings:app:allow:unsecure:http:description": "Allow the use of <b class='text-error-500'>unsecure HTTP</b> target website during creation of snapps.",
"settings:app:home:label": "Disable homepage",
"settings:app:private:saved": "Preferences updated",
"settings:app:sign:up:description": "Allow external signups to this app.",