🚧 Added Proof of Work on image-upload and more
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
import * as yup from 'yup';
|
||||
import { mint } from '$lib/hashcash';
|
||||
import { dataSchema } from '$lib/yupSchemas';
|
||||
import type { EditorData, Question, Answer } from './quiz_types';
|
||||
import Sidebar from '$lib/editor/sidebar.svelte';
|
||||
import SettingsCard from '$lib/editor/settings-card.svelte';
|
||||
import QuizCard from '$lib/editor/card.svelte';
|
||||
import Spinner from './Spinner.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
@@ -67,6 +68,7 @@
|
||||
};
|
||||
let edit_id;
|
||||
let confirm_to_leave = true;
|
||||
let pow_data;
|
||||
|
||||
const getEditID = async () => {
|
||||
let res;
|
||||
@@ -82,7 +84,7 @@
|
||||
if (res.status === 200) {
|
||||
const json = await res.json();
|
||||
edit_id = json.token;
|
||||
console.log(edit_id, json);
|
||||
setPOWdata();
|
||||
} else {
|
||||
alert('Error!');
|
||||
}
|
||||
@@ -110,7 +112,6 @@
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
if (res.ok) {
|
||||
console.log('Hier');
|
||||
confirm_to_leave = false;
|
||||
console.log(confirm_to_leave);
|
||||
window.location.href = '/overview';
|
||||
@@ -118,6 +119,13 @@
|
||||
alert('Error');
|
||||
}
|
||||
};
|
||||
const setPOWdata = async () => {
|
||||
const res = await fetch(`/api/v1/editor/pow?edit_id=${edit_id}`);
|
||||
const data = (await res.json()).data;
|
||||
console.log(data);
|
||||
pow_data = await mint(data);
|
||||
console.log(pow_data);
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:window on:beforeunload={confirmUnload} />
|
||||
@@ -167,7 +175,7 @@
|
||||
{#if selected_question === -1}
|
||||
<SettingsCard bind:data />
|
||||
{:else}
|
||||
<QuizCard bind:data bind:selected_question bind:edit_id />
|
||||
<QuizCard bind:data bind:selected_question bind:edit_id bind:pow_data />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
export let data: EditorData;
|
||||
export let selected_question: number;
|
||||
export let edit_id: string;
|
||||
export let pow_data;
|
||||
const empty_answer: Answer = {
|
||||
right: false,
|
||||
answer: ''
|
||||
@@ -67,6 +68,8 @@
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else if pow_data === undefined}
|
||||
<Spinner />
|
||||
{:else}
|
||||
{#await import('$lib/editor/uploader.svelte')}
|
||||
<Spinner />
|
||||
@@ -77,6 +80,7 @@
|
||||
bind:edit_id
|
||||
bind:data
|
||||
bind:selected_question
|
||||
bind:pow_data
|
||||
/>
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
export let edit_id: string;
|
||||
export let data: EditorData;
|
||||
export let selected_question: number;
|
||||
export let pow_data;
|
||||
|
||||
console.log(pow_data);
|
||||
const uppy = new Uppy()
|
||||
.use(DropTarget, {
|
||||
target: document.body
|
||||
@@ -34,7 +36,7 @@
|
||||
quality: 0.6
|
||||
})
|
||||
.use(XHRUpload, {
|
||||
endpoint: `/api/v1/editor/image?edit_id=${edit_id}`
|
||||
endpoint: `/api/v1/editor/image?edit_id=${edit_id}&pow_data=${pow_data}`
|
||||
});
|
||||
const props = { inline: true };
|
||||
let image_id;
|
||||
@@ -42,6 +44,7 @@
|
||||
image_id = response.body.id;
|
||||
});
|
||||
uppy.on('complete', (res) => {
|
||||
console.log(pow_data);
|
||||
data.questions[
|
||||
selected_question
|
||||
].image = `${window.location.origin}/api/v1/storage/download/${image_id}`;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
const gen_salt = (l: number): string => {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const charLength = chars.length;
|
||||
let result = '';
|
||||
for (let i = 0; i < l; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * charLength));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const mint = async (
|
||||
resource: string,
|
||||
bits = 19,
|
||||
now = null,
|
||||
ext = '',
|
||||
saltchars = 8,
|
||||
stamp_seconds = false
|
||||
): Promise<string> => {
|
||||
const ver = '1';
|
||||
let ts;
|
||||
if (stamp_seconds) {
|
||||
ts = DateTime.now().toFormat('yyMMddHHmmss');
|
||||
} else {
|
||||
ts = DateTime.now().toFormat('yyMMdd');
|
||||
}
|
||||
const hex_digits = Math.ceil(bits / 4);
|
||||
const zeros = '0'.repeat(hex_digits);
|
||||
const salt = gen_salt(saltchars);
|
||||
const challenge = `${ver}:${bits}:${ts}:${resource}:${ext}:${salt}`;
|
||||
let digest: string;
|
||||
let counter = 0;
|
||||
let result: string;
|
||||
while (true) {
|
||||
const data = new TextEncoder().encode(`${challenge}:${counter.toString(16)}`);
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-1', data);
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const digest = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
||||
if (digest.slice(0, hex_digits) == zeros) {
|
||||
result = counter.toString(16);
|
||||
break;
|
||||
}
|
||||
counter += 1;
|
||||
}
|
||||
return `${challenge}:${result}`;
|
||||
};
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
import LandingPromo from '$lib/landing/landing-promo.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { mint } from '$lib/hashcash';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user