@axium/server 0.41.1 → 0.42.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/admin.js +1 -1
- package/dist/api/images.d.ts +11 -0
- package/dist/api/{pfp.js → images.js} +26 -22
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/auth.js +2 -2
- package/dist/config.js +1 -1
- package/dist/db/connection.js +5 -0
- package/package.json +3 -3
- package/routes/account/+page.svelte +1 -1
- package/routes/admin/plugins/+page.svelte +2 -4
- package/dist/api/pfp.d.ts +0 -1
package/dist/api/admin.js
CHANGED
|
@@ -66,7 +66,7 @@ addRoute({
|
|
|
66
66
|
error(404, 'Plugin not found');
|
|
67
67
|
}
|
|
68
68
|
if (config) {
|
|
69
|
-
const
|
|
69
|
+
const schema = serverConfigs.get(name) || null;
|
|
70
70
|
if (!schema)
|
|
71
71
|
error(400, 'Plugin does not have a configuration schema');
|
|
72
72
|
if (!plugin._configPath)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ImageUploadConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
/** Max size in KB */
|
|
4
|
+
max_size: number;
|
|
5
|
+
/** Max pixels per dimension */
|
|
6
|
+
max_length: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function checkImageUpload(request: Request, cfg: ImageUploadConfig, userId: string): Promise<{
|
|
9
|
+
data: Uint8Array<ArrayBuffer>;
|
|
10
|
+
type: string;
|
|
11
|
+
}>;
|
|
@@ -26,6 +26,31 @@ catch {
|
|
|
26
26
|
warn('Can not determine profile picture dimensions because neither image-size or ImageMagick is available');
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
export async function checkImageUpload(request, cfg, userId) {
|
|
30
|
+
const { enabled, max_size, max_length } = cfg;
|
|
31
|
+
if (!enabled)
|
|
32
|
+
error(503, 'Image uploads are disabled');
|
|
33
|
+
await checkAuthForUser(request, userId);
|
|
34
|
+
const type = request.headers.get('content-type');
|
|
35
|
+
if (!type)
|
|
36
|
+
error(400, 'Missing Content-Type header');
|
|
37
|
+
if (!type.startsWith('image/'))
|
|
38
|
+
error(415, 'Only image files are allowed');
|
|
39
|
+
const size = Number(request.headers.get('content-length'));
|
|
40
|
+
if (!Number.isSafeInteger(size))
|
|
41
|
+
error(400, 'Invalid Content-Length header');
|
|
42
|
+
if (max_size && size / 1000 > max_size)
|
|
43
|
+
error(413, `Image must be smaller than ${max_size} KB`);
|
|
44
|
+
const data = await request.bytes();
|
|
45
|
+
if (data.byteLength != size)
|
|
46
|
+
error(400, 'Content-Length does not match actual data size');
|
|
47
|
+
const { width, height } = imageSize?.(data) || { width: 0, height: 0 };
|
|
48
|
+
if (imageSize && (!width || !height))
|
|
49
|
+
error(400, 'Invalid image dimensions');
|
|
50
|
+
if (max_length && (width > max_length || height > max_length))
|
|
51
|
+
error(413, `Image must be smaller than ${max_length}x${max_length} pixels`);
|
|
52
|
+
return { data, type };
|
|
53
|
+
}
|
|
29
54
|
addRoute({
|
|
30
55
|
path: '/raw/pfp/:id',
|
|
31
56
|
params: { id: z.uuid() },
|
|
@@ -76,28 +101,7 @@ addRoute({
|
|
|
76
101
|
});
|
|
77
102
|
},
|
|
78
103
|
async POST(request, { id: userId }) {
|
|
79
|
-
const {
|
|
80
|
-
if (!enabled)
|
|
81
|
-
error(503, 'Custom profile pictures are disabled');
|
|
82
|
-
await checkAuthForUser(request, userId);
|
|
83
|
-
const type = request.headers.get('content-type');
|
|
84
|
-
if (!type)
|
|
85
|
-
error(400, 'Missing Content-Type header');
|
|
86
|
-
if (!type.startsWith('image/'))
|
|
87
|
-
error(415, 'Only image files are allowed');
|
|
88
|
-
const size = Number(request.headers.get('content-length'));
|
|
89
|
-
if (!Number.isSafeInteger(size))
|
|
90
|
-
error(400, 'Invalid Content-Length header');
|
|
91
|
-
if (max_size && size / 1000 > max_size)
|
|
92
|
-
error(413, `Profile picture must be smaller than ${max_size} KB`);
|
|
93
|
-
const data = await request.bytes();
|
|
94
|
-
if (data.byteLength != size)
|
|
95
|
-
error(400, 'Content-Length does not match actual data size');
|
|
96
|
-
const { width, height } = imageSize?.(data) || { width: 0, height: 0 };
|
|
97
|
-
if (imageSize && (!width || !height))
|
|
98
|
-
error(400, 'Invalid image dimensions');
|
|
99
|
-
if (max_length && (width > max_length || height > max_length))
|
|
100
|
-
error(413, `Profile picture must be smaller than ${max_length}x${max_length} pixels`);
|
|
104
|
+
const { data, type } = await checkImageUpload(request, config.user_pfp, userId);
|
|
101
105
|
const { isInsert } = await db
|
|
102
106
|
.insertInto('profile_pictures')
|
|
103
107
|
.values({ userId, data, type })
|
package/dist/api/index.d.ts
CHANGED
package/dist/api/index.js
CHANGED
package/dist/auth.js
CHANGED
|
@@ -51,8 +51,8 @@ export async function getSession(sessionId) {
|
|
|
51
51
|
export async function requireSession(request, sensitive = false) {
|
|
52
52
|
const token = getToken(request, sensitive);
|
|
53
53
|
if (!token)
|
|
54
|
-
error(401, 'Missing session
|
|
55
|
-
const session = await getSessionAndUser(token).catch(withError('Invalid or expired session
|
|
54
|
+
error(401, 'Missing session (you are not logged in)');
|
|
55
|
+
const session = await getSessionAndUser(token).catch(withError('Invalid or expired session', 401));
|
|
56
56
|
if (session.user.isSuspended)
|
|
57
57
|
error(403, 'User is suspended');
|
|
58
58
|
return session;
|
package/dist/config.js
CHANGED
|
@@ -253,7 +253,7 @@ export async function loadConfig(path, options = {}) {
|
|
|
253
253
|
if (!existsSync(configPath))
|
|
254
254
|
continue;
|
|
255
255
|
try {
|
|
256
|
-
const data = io.readJSON(configPath, serverConfig.
|
|
256
|
+
const data = io.readJSON(configPath, serverConfig.partial());
|
|
257
257
|
deepAssign(plugin.config, data, true);
|
|
258
258
|
io.debug(`Loaded config for plugin ${plugin.name} from ${configPath}`);
|
|
259
259
|
}
|
package/dist/db/connection.js
CHANGED
|
@@ -11,6 +11,11 @@ export function connect() {
|
|
|
11
11
|
return (database = globalThis[sym]);
|
|
12
12
|
database = new Kysely({
|
|
13
13
|
dialect: new PostgresDialect({ pool: new pg.Pool(config.db) }),
|
|
14
|
+
log(event) {
|
|
15
|
+
if (event.level != 'error')
|
|
16
|
+
return;
|
|
17
|
+
io.error('Query failed:', event.query.sql);
|
|
18
|
+
},
|
|
14
19
|
});
|
|
15
20
|
globalThis[sym] = database;
|
|
16
21
|
io.debug('Connected to database!');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.1",
|
|
4
4
|
"author": "James Prevett <axium@jamespre.dev>",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@axium/client": ">=0.21.0",
|
|
51
|
-
"@axium/core": ">=0.
|
|
51
|
+
"@axium/core": ">=0.26.0",
|
|
52
52
|
"kysely": "^0.28.0",
|
|
53
|
-
"utilium": "^
|
|
53
|
+
"utilium": "^3.0.0",
|
|
54
54
|
"zod": "^4.0.5"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { PageProps } from './$types';
|
|
8
8
|
import { toast, toastStatus } from '@axium/client/toast';
|
|
9
9
|
import { contextMenu } from '@axium/client/attachments';
|
|
10
|
-
import { upload } from 'utilium/dom
|
|
10
|
+
import { upload } from 'utilium/dom';
|
|
11
11
|
|
|
12
12
|
const { data }: PageProps = $props();
|
|
13
13
|
const { canVerify } = data;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<h2>{text('page.admin.plugins.heading')}</h2>
|
|
17
17
|
|
|
18
18
|
{#each data.plugins as plugin}
|
|
19
|
-
{@const
|
|
19
|
+
{@const schema = serverConfigs.get(plugin.name)}
|
|
20
20
|
<div class="plugin">
|
|
21
21
|
<h3>
|
|
22
22
|
{plugin.name}<Version
|
|
@@ -46,14 +46,12 @@
|
|
|
46
46
|
{:else}<i>{text('generic.none')}</i>{/if}
|
|
47
47
|
</p>
|
|
48
48
|
<p>{plugin.description}</p>
|
|
49
|
-
{#if
|
|
49
|
+
{#if schema && plugin.config}
|
|
50
50
|
<h4>{text('page.admin.plugins.configuration')}</h4>
|
|
51
|
-
{@const { schema, labels } = cfg}
|
|
52
51
|
<ZodForm
|
|
53
52
|
rootValue={plugin.config}
|
|
54
53
|
idPrefix={plugin.name}
|
|
55
54
|
{schema}
|
|
56
|
-
{labels}
|
|
57
55
|
updateValue={config => fetchAPI('POST', 'admin/plugins', { plugin: plugin.name, config })}
|
|
58
56
|
/>
|
|
59
57
|
{/if}
|
package/dist/api/pfp.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|