Skip to content

Commit

Permalink
Merge pull request #89 from significa/drawing-authorization
Browse files Browse the repository at this point in the history
Added drawing (segg) authorization
  • Loading branch information
tofran authored May 15, 2023
2 parents f665ed2 + 16856e6 commit e2d006f
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 53 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ NOTION_DB_CONTACTS=

BYPASS_TOKEN=

VITE_HTTPS_ENABLED=true
VITE_HTTPS_ENABLED=true

SESSION_SECRET_KEY=
12 changes: 6 additions & 6 deletions src/components/draw-your-segg/draw-your-segg.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
export let template = base;
// save drawing in DB
let dbId: string | null = null;
let id: string | null = null;
let authToken: string | null = null;
const save = async (drawing: Drawing) => {
const res = await fetch('/segg', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: dbId, drawing })
body: JSON.stringify({ id, authToken, drawing })
});
// save ID
if (res.ok) {
dbId = await res.json();
({ id, authToken } = await res.json());
}
};
</script>
Expand All @@ -34,7 +34,7 @@
<div class="dots" />
</div>
<div class="relative overflow-hidden rounded-lg">
<Canvas id={dbId} {width} {height} on:change={({ detail }) => save(detail)} {template} />
<Canvas {id} {width} {height} on:change={({ detail }) => save(detail)} {template} />
<div class="dots" />
</div>
</div>
Expand Down
37 changes: 37 additions & 0 deletions src/lib/drawings.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import zlib from 'zlib';
import { env } from '$env/dynamic/private';
import { dynamoDbClient } from '$lib/aws.server.js';
import { PutItemCommand, GetItemCommand } from '@aws-sdk/client-dynamodb';
import { error } from '@sveltejs/kit';

export const createOrUpdateDrawing = async (drawing: unknown, id?: string) => {
id = id || crypto.randomUUID();

const payload = {
TableName: env.AWS_DYNAMODB_TABLE,
Item: {
id: { S: id },
drawing: { B: zlib.gzipSync(JSON.stringify(drawing)) },
created_at: { S: new Date().toISOString() }
}
};

await dynamoDbClient.send(new PutItemCommand(payload));

return id;
};

export const getDrawing = async (id: string) => {
const { Item } = await dynamoDbClient.send(
new GetItemCommand({
TableName: env.AWS_DYNAMODB_TABLE,
Key: {
id: { S: id }
}
})
);

if (!Item || !Item.drawing.B) throw error(404, 'Not found');

return JSON.parse(zlib.gunzipSync(Item.drawing.B).toString());
};
59 changes: 36 additions & 23 deletions src/routes/segg/+server.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
import zlib from 'zlib';
import { env } from '$env/dynamic/private';
import { dynamoDbClient } from '$lib/aws.server.js';
import { PutItemCommand } from '@aws-sdk/client-dynamodb';
import { error, json } from '@sveltejs/kit';

export async function POST({ request }) {
import { createHmac } from 'crypto';
import { createOrUpdateDrawing } from '$lib/drawings.server.js';
import { isValidDrawing } from '$components/draw-your-segg/types.js';

const getAuthToken = (id: string) => {
const hmac = createHmac('sha256', env.SESSION_SECRET_KEY);
hmac.update(id);
return hmac.digest('hex');
};

const isValidUUID4 = (uuid: string) => {
const UUID_REGEX = /^[0-9a-f]{8}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{12}$/;

if (!uuid) {
return false;
}
const uuidString = uuid.toString();
return uuidString.match(UUID_REGEX) !== null;
};

export const POST = async ({ request }) => {
const body = await request.json();

const getPutCommand = (id: string) => {
return new PutItemCommand({
TableName: env.AWS_DYNAMODB_TABLE,
Item: {
id: { S: id },
drawing: { B: zlib.gzipSync(JSON.stringify(body.drawing)) },
created_at: { S: new Date().toISOString() }
}
});
};

try {
const id = body.id || crypto.randomUUID();
dynamoDbClient.send(getPutCommand(id));
return json(id);
} catch (err) {
console.error(err);
throw error(422);
let id = body.id;
const drawing = body.drawing;

if (!isValidDrawing(drawing)) throw error(422);

if (id && (!isValidUUID4(id) || getAuthToken(id) !== body.authToken)) {
throw error(403);
}
}

id = await createOrUpdateDrawing(drawing, id);

return json({
id,
authToken: getAuthToken(id)
});
};
27 changes: 4 additions & 23 deletions src/routes/segg/[segg]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,15 @@
import zlib from 'zlib';
import { isValidDrawing } from '$components/draw-your-segg/types.js';
import { env } from '$env/dynamic/private';
import { dynamoDbClient } from '$lib/aws.server.js';
import { GetItemCommand } from '@aws-sdk/client-dynamodb';
import { error } from '@sveltejs/kit';
import { getDrawing } from '$lib/drawings.server.js';

export const load = async ({ params }) => {
if (!params.segg) {
throw error(400, 'Not found');
}

try {
const { Item } = await dynamoDbClient.send(
new GetItemCommand({
TableName: env.AWS_DYNAMODB_TABLE,
Key: {
id: { S: params.segg }
}
})
);
const drawing = await getDrawing(params.segg);

if (!Item || !Item.drawing.B) throw error(404, 'Not found');
if (!isValidDrawing(drawing)) throw error(404, 'Not found');

const drawing = JSON.parse(zlib.gunzipSync(Item.drawing.B).toString());

if (!isValidDrawing(drawing)) throw new Error('Invalid drawing');

return { drawing };
} catch (err) {
console.error(err);
throw error(404, 'Not found');
}
return { drawing };
};

0 comments on commit e2d006f

Please sign in to comment.