Skip to content

Commit

Permalink
added: expire timer
Browse files Browse the repository at this point in the history
  • Loading branch information
scolastico committed Mar 29, 2024
1 parent d0be984 commit 9b04215
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 25 deletions.
93 changes: 79 additions & 14 deletions components/nav-bar.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<template>
<yes-no
title="Are you sure?"
:message="warning"
:visible="visible"
@yes="copyDecrypted"
@no="visible = false"
/>
<div class="w-screen flex gap-2 bg-black text-white px-2 py-1">
<h1 class="font-bold select-none">not-th.re</h1>
<div class="w-screen flex gap-2 bg-black text-white px-4 py-1 items-center">
<yes-no
title="Are you sure?"
:message="warning"
:visible="visible"
@yes="copyDecrypted"
@no="visible = false"
/>
<img id="logo" src="/assets/img/icon.svg" class="h-5 w-5 border-white border" alt="!3" />
<h1 class="font-bold select-none transition-all duration-200 max-w-0 -mr-1 overflow-hidden whitespace-pre">
not-th.re
</h1>
<nav-entry
v-for="entry in entries"
:name="entry.name"
Expand All @@ -16,25 +19,87 @@
:disabled="entry.disabled"
@click="handle"
/>
<div class="flex-grow" />
<template v-if="expires" title="Time until this file is deleted">
<icon name="lucide:alarm-clock" />
<span class="font-mono translate-y-0.5">{{ expiresString }}</span>
</template>
</div>
</template>

<style>
#logo:hover + h1 {
@apply max-w-32 mr-0;
}
</style>

<script lang="ts" setup>
const props = defineProps<{
config: any;
defaultExpires: number;
expires?: number|null;
}>()
const expiresObject = ref({ hours: 0, minutes: 0, seconds: 0 })
const expiresString = ref('XX:XX:XX')
const scheduler = ref(0)
watch(() => props.expires, (value) => {
if (!props.expires) {
clearTimeout(scheduler.value)
return
}
const expiresDate = new Date(props.expires)
const currentDate = new Date();
const diff = expiresDate.getTime() - currentDate.getTime();
expiresObject.value = {
seconds: Math.floor(diff / 1000) % 60,
minutes: Math.floor(diff / 1000 / 60) % 60,
hours: Math.floor(diff / 1000 / 60 / 60),
}
const update = () => {
const { hours, minutes, seconds } = expiresObject.value
expiresObject.value.seconds--
if (expiresObject.value.seconds < 0) {
expiresObject.value.seconds = 59
expiresObject.value.minutes--
}
if (expiresObject.value.minutes < 0) {
expiresObject.value.minutes = 59
expiresObject.value.hours--
}
expiresString.value = [
hours.toString().padStart(2, '0'),
minutes.toString().padStart(2, '0'),
seconds.toString().padStart(2, '0'),
].join(':')
if (hours === 0 && minutes === 0 && seconds === 0) return;
scheduler.value = window.setTimeout(update, 1000)
}
update()
}, { immediate: true })
onUnmounted(() => {
clearTimeout(scheduler.value)
})
const visible = ref(false)
const route = useRoute()
const warning = [
'With this url the server will be able to decrypt your data.',
'This has it\'s benefits, and we do not store the data, but',
'it\'s still a risk. Are you sure you want to share this url?',
].join(' ')
console.log(route.params.id)
const entries = [
const entries = computed(() => ([
{
name: 'file',
entries: ['save', 'duplicate', 'new'],
entries: [
['save', 'Save for ' + Math.floor(props.defaultExpires / 1000 / 60 / 60 / 24) + ' days'],
['duplicate', 'Duplicate'],
['new', 'New'],
] as [string, string][],
},
{
name: 'share',
Expand All @@ -53,7 +118,7 @@ const entries = [
['terms', 'Privacy and Terms'],
] as [string, string][],
}
]
]))
const emit = defineEmits(['save', 'duplicate', 'new'])
Expand All @@ -74,7 +139,7 @@ function handle(entry: string) {
switch (entry) {
case 'share-curl':
navigator.clipboard.writeText([
`curl ${url}raw/${route.params.id}| base64 -d |`,
`curl ${url}raw/${route.params.id} | base64 -d |`,
`openssl enc -aes-256-cbc -d -pass pass:${location.hash.substring(1)}`,
'-md md5 -salt -in /dev/stdin 2>/dev/null | cat',
].join(' '))
Expand Down
10 changes: 6 additions & 4 deletions components/nav-entry.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="border-l-2 border-white/20" />
<div class="border-l-2 border-white/20 h-full content-['']" />
<div class="relative" ref="container">
<h2
@click="active = disabled ? false : !active"
Expand All @@ -9,9 +9,9 @@
<span class="font-bold">{{ name.substring(0, 1).toUpperCase() }}</span>
<span>{{ name.substring(1) }}</span>
</h2>
<div class="absolute inset-x-0 bottom-0 flex justify-center items-center pointer-events-none">
<div class="absolute inset-x-0 bottom-0 flex justify-start items-center pointer-events-none">
<fade>
<div v-if="active" class="translate-y-full overflow-visible z-50 flex flex-col items-center pointer-events-auto">
<div v-if="active" class="translate-y-full overflow-visible z-50 flex flex-col items-start pointer-events-auto">
<div class="w-0 h-0 border-x-[1rem] border-x-transparent border-b-[1rem] border-b-black mt-2" />
<div class="bg-black p-2">
<button
Expand Down Expand Up @@ -50,7 +50,7 @@ function doEmit(entry: string) {
emit('click', entry)
}
function outsideClickListener(event: MouseEvent) {
function outsideClickListener(event: MouseEvent | TouchEvent) {
if (!container.value) return
if (!container.value.contains(event.target as Node)) {
active.value = false
Expand All @@ -59,9 +59,11 @@ function outsideClickListener(event: MouseEvent) {
onMounted(() => {
window.addEventListener('click', outsideClickListener)
window.addEventListener('touchstart', outsideClickListener)
})
onUnmounted(() => {
window.removeEventListener('click', outsideClickListener)
window.removeEventListener('touchstart', outsideClickListener)
})
</script>
17 changes: 13 additions & 4 deletions mixins/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,25 @@ export default defineNuxtComponent({
api: null as any,
errorVisible: false,
errorMessage: '',
defaultExpires: 0,
}),
mounted() {
async mounted() {
const handler = (event: any) => {
if (event.origin !== location.origin) return;
if (event.data?.type !== 'DUPLICATE_SHARE') return;
this.content = event.data.content;
window.removeEventListener('message', handler);
}
window.addEventListener('message', handler);
this.getApi()
const api = await this.getApi()
try {
const info = await api.get('info');
this.defaultExpires = info.data.defaultExpires;
} catch (e) {
console.error(e);
this.errorMessage = 'Error connecting to API. Please try again later.';
this.errorVisible = true;
}
},
methods: {
async showError(message: string) {
Expand All @@ -32,8 +41,8 @@ export default defineNuxtComponent({
const secret = Math.random().toString(36).substring(2);
const encrypted = CryptoJS.AES.encrypt(this.content, secret).toString();
const res = await (await this.getApi()).post('create', { content: encrypted });
window.location.href = `/q/${res.data.id}#${secret}`;
console.log(res.data, secret);
// window.location.href = `/q/${res.data.id}#${secret}`;
this.$router.push('/q/' + res.data.id + '#' + secret);
},
async duplicateD() {
if (!this.content) return this.showError('No content to duplicate');
Expand Down
1 change: 1 addition & 0 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<spinner :visible="loading" />
<nav-bar
:config="configData"
:default-expires="defaultExpires"
@new="newD"
@save="saveD"
@duplicate="duplicateD"
Expand Down
10 changes: 7 additions & 3 deletions pages/q/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<spinner :visible="loading" />
<nav-bar
:config="configData"
:expires="expires"
:default-expires="defaultExpires"
@new="newD"
@save="saveD"
@duplicate="duplicateD"
Expand All @@ -34,19 +36,21 @@ export default defineNuxtComponent({
data: () => ({
isReady: false,
decryptURL: '',
expires: null,
}),
async mounted() {
try {
const api = await this.getApi();
const secret = location.hash.substring(1);
this.decryptURL = api.defaults.baseURL + `decrypt/${this.$route.params.id}/${secret}`;
const res = await (await this.getApi()).get(`raw/${this.$route.params.id}`);
this.content = CryptoJS.AES.decrypt(res.data, secret).toString(CryptoJS.enc.Utf8);
const res = await api.get(`json/${this.$route.params.id}`);
this.content = CryptoJS.AES.decrypt(res.data.content, secret).toString(CryptoJS.enc.Utf8);
this.isReady = true;
this.readOnly = true;
this.expires = res.data.expires;
} catch (e) {
console.error(e);
window.location.href = '/';
this.$router.push('/');
}
},
})
Expand Down

0 comments on commit 9b04215

Please sign in to comment.