sdadsfsdfdsfa

This commit is contained in:
Skye 2023-03-05 19:04:55 +09:00
parent 6abbd6b2c0
commit 8dae161d7c
Signed by: me
GPG key ID: 0104BC05F41B77B8
10 changed files with 338 additions and 43 deletions

View file

@ -44,6 +44,7 @@
"dependencies": { "dependencies": {
"@auth/core": "^0.5.0", "@auth/core": "^0.5.0",
"@auth/sveltekit": "^0.2.2", "@auth/sveltekit": "^0.2.2",
"@ltd/j-toml": "^1.38.0",
"@rgossiaux/svelte-headlessui": "^1.0.2", "@rgossiaux/svelte-headlessui": "^1.0.2",
"@xmcl/modrinth": "^1.1.0", "@xmcl/modrinth": "^1.1.0",
"minio": "^7.0.32", "minio": "^7.0.32",
@ -51,7 +52,6 @@
"nanoid": "^4.0.1", "nanoid": "^4.0.1",
"octokit": "^2.0.14", "octokit": "^2.0.14",
"svelte-feather-icons": "^4.0.0", "svelte-feather-icons": "^4.0.0",
"toml": "^3.0.0",
"zod": "^3.20.6" "zod": "^3.20.6"
} }
} }

16
src/lib/clients.ts Normal file
View file

@ -0,0 +1,16 @@
import Nano from 'nano';
import Minio from 'minio';
import {
COUCHDB_URL,
S3_ACCESS_KEY_ID,
S3_ENDPOINT,
S3_SECRET_ACCESS_KEY
} from '$env/static/private';
export const nano = Nano(COUCHDB_URL);
export const minioClient = new Minio.Client({
endPoint: S3_ENDPOINT,
useSSL: true,
accessKey: S3_ACCESS_KEY_ID,
secretKey: S3_SECRET_ACCESS_KEY
});

145
src/lib/packwiz-types.ts Normal file
View file

@ -0,0 +1,145 @@
import { z } from 'zod';
export const packSchema = z.object({
index: z.object({
file: z.string(),
'hash-format': z.enum(['sha256', 'sha512', 'sha1', 'md5', 'murmur2']),
hash: z.string().regex(/^[a-fA-F0-9]+$/)
}),
name: z.string(),
'pack-format': z.string().default('packwiz:1.0.0'),
versions: z.object({
minecraft: z.string(),
fabric: z.string().optional(),
forge: z.string().optional(),
liteloader: z.string().optional(),
quilt: z.string().optional()
}),
author: z.string().optional(),
description: z.string().optional(),
version: z.string().optional()
});
export const indexSchema = z.object({
'hash-format': z.enum(['sha256', 'sha512', 'sha1', 'md5', 'murmur2']),
files: z
.object({
file: z.string(),
hash: z.string().regex(/^[a-fA-F0-9]+$/),
alias: z.string(),
'hash-format': z.enum(['sha256', 'sha512', 'sha1', 'md5', 'murmur2']),
metafile: z.boolean().default(false),
preserve: z.boolean().default(false)
})
.array(),
update: z
.object({
curseforge: z
.object({
'file-id': z.number(),
'project-id': z.number()
})
.optional(),
modrinth: z
.object({
'mod-id': z.string(),
version: z.string()
})
.optional()
})
.default({})
});
// export const metafileSchema = z.object({
// download: z.object({
// 'hash-format': z.enum(['sha256', 'sha512', 'sha1', 'md5', 'murmur2']),
// hash: z.string().regex(/^[a-fA-F0-9]+$/),
// url: z.string().url().optional(),
// mode: z.enum(['url', 'metadata:curseforge']).default('url')
// }),
// filename: z.string(),
// name: z.string(),
// option: z
// .object({
// optional: z.boolean(),
// default: z.boolean().default(false),
// description: z.string().optional()
// })
// .default({ optional: false }),
// side: z.enum(['server', 'client', 'both']).default('both'),
// update: z
// .object({
// curseforge: z
// .object({
// 'file-id': z.bigint(),
// 'project-id': z.bigint()
// })
// .optional(),
// modrinth: z
// .object({
// 'mod-id': z.string(),
// version: z.string()
// })
// .optional()
// })
// .default({})
// });
const metafileBase = z.object({
filename: z.string(),
name: z.string(),
option: z
.object({
optional: z.boolean(),
default: z.boolean().default(false),
description: z.string().optional()
})
.default({ optional: false }),
side: z.enum(['server', 'client', 'both']).default('both')
});
export const metafileSchema = z.union([
metafileBase.extend({
download: z.object({
'hash-format': z.enum(['sha256', 'sha512', 'sha1', 'md5', 'murmur2']),
hash: z.string().regex(/^[a-fA-F0-9]+$/),
url: z.string().url(),
mode: z.literal('url').default('url')
}),
update: z
.object({
curseforge: z
.object({
'file-id': z.bigint(),
'project-id': z.bigint()
})
.optional(),
modrinth: z
.object({
'mod-id': z.string(),
version: z.string()
})
.optional()
})
.default({})
}),
metafileBase.extend({
download: z.object({
'hash-format': z.enum(['sha256', 'sha512', 'sha1', 'md5', 'murmur2']),
hash: z.string().regex(/^[a-fA-F0-9]+$/),
mode: z.literal('metadata:curseforge')
}),
update: z.object({
curseforge: z.object({
'file-id': z.bigint(),
'project-id': z.bigint()
}),
modrinth: z
.object({
'mod-id': z.string(),
version: z.string()
})
.optional()
})
})
]);

View file

@ -10,15 +10,15 @@ export const fileInlineSchema = z.object({
inline: z.literal(true), inline: z.literal(true),
metafile: z.boolean(), metafile: z.boolean(),
content: z.string().max(256 * 1024), content: z.string().max(256 * 1024),
sha1: z.string().regex(/^[a-fA-F0-9]{40}$/), sha1: z.string().regex(/^[a-f0-9]{40}$/),
sha512: z.string().regex(/^[a-fA-F0-9]{128}$/) sha512: z.string().regex(/^[a-f0-9]{128}$/)
}); });
export const fileBlobSchema = z.object({ export const fileBlobSchema = z.object({
type: z.literal('file'), type: z.literal('file'),
inline: z.literal(false), inline: z.literal(false),
sha1: z.string().regex(/^[a-fA-F0-9]{40}$/), sha1: z.string().regex(/^[a-f0-9]{40}$/),
sha512: z.string().regex(/^[a-fA-F0-9]{128}$/) sha512: z.string().regex(/^[a-f0-9]{128}$/)
}); });
export const fileSchema = z.union([fileInlineSchema, fileBlobSchema]); export const fileSchema = z.union([fileInlineSchema, fileBlobSchema]);

View file

@ -1 +1,2 @@
Front Page Here Front Page Here
<a href="/create">create</a>

View file

@ -1,33 +1,16 @@
import type { Actions } from './$types'; import type { Actions } from './$types';
import Nano from 'nano'; import { COUCHDB_DB_NAME, S3_BUCKET_NAME } from '$env/static/private';
import Minio from 'minio';
import {
COUCHDB_URL,
COUCHDB_DB_NAME,
S3_ACCESS_KEY_ID,
S3_BUCKET_NAME,
S3_ENDPOINT,
S3_SECRET_ACCESS_KEY
} from '$env/static/private';
import { fail, redirect } from '@sveltejs/kit'; import { fail, redirect } from '@sveltejs/kit';
import { fileTreeSchema } from '$lib/types-zod'; import { fileTreeSchema } from '$lib/types-zod';
import { get_blobs } from '$lib/utils'; import { get_blobs } from '$lib/utils';
import type { Modpack } from '$lib/types'; import type { Modpack } from '$lib/types';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { minioClient, nano } from '$lib/clients';
const nano = Nano(COUCHDB_URL);
const minioClient = new Minio.Client({
endPoint: S3_ENDPOINT,
useSSL: true,
accessKey: S3_ACCESS_KEY_ID,
secretKey: S3_SECRET_ACCESS_KEY
});
export const actions: Actions = { export const actions: Actions = {
default: async (event) => { default: async (event) => {
const session = await event.locals.getSession(); const session = await event.locals.getSession();
if (!session?.user) throw redirect(303, '/auth'); if (!session?.user) throw redirect(303, '/auth/signin');
const data = await event.request.formData(); const data = await event.request.formData();
const payload = data.get('payload'); const payload = data.get('payload');
const title = data.get('title'); const title = data.get('title');
@ -45,7 +28,10 @@ export const actions: Actions = {
const buf = await file.arrayBuffer(); const buf = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-512', buf); const hashBuffer = await crypto.subtle.digest('SHA-512', buf);
const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashArray = Array.from(new Uint8Array(hashBuffer));
const hash = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); const hash = hashArray
.map((b) => b.toString(16).padStart(2, '0'))
.join('')
.toLowerCase();
if (hash != blob.sha512) throw fail(400); if (hash != blob.sha512) throw fail(400);
let exists = false; let exists = false;
try { try {
@ -63,12 +49,14 @@ export const actions: Actions = {
_id: nanoid(), _id: nanoid(),
name: title, name: title,
author: session.user.email ?? 'unknown@nodomain', author: session.user.email ?? 'unknown@nodomain',
revisions: [{ revisions: [
{
id: nanoid(), id: nanoid(),
type: 'base', type: 'base',
tree: payload_decoded.data, tree: payload_decoded.data,
message: 'initial revision' message: 'initial revision'
}] }
]
}; };
await nano.use(COUCHDB_DB_NAME).insert(document); await nano.use(COUCHDB_DB_NAME).insert(document);
} }

View file

@ -1,7 +1,103 @@
<script lang="ts"> <script lang="ts">
import type { PageData } from './$types'; import FlattenedFileList from './FlattenedFileList.svelte';
export let data: PageData; import type { Folder } from '$lib/types';
import {
Tab,
TabGroup,
TabList,
TabPanel,
TabPanels,
Dialog,
DialogOverlay,
DialogTitle,
DialogDescription
} from '@rgossiaux/svelte-headlessui';
import { PlusIcon } from 'svelte-feather-icons';
let fileTree: Folder = {
type: 'folder',
children: {
mods: { type: 'folder', children: {
"quark.pw.toml": {
type: 'file',
inline: true,
metafile: true,
content: `name = "Quark"
filename = "Quark-3.4-389.jar"
side = "both"
[download]
hash-format = "sha1"
hash = "9a2fcfae363db7330abc7a658bc7e016ae72fb5e"
mode = "metadata:curseforge"
[update]
[update.curseforge]
file-id = 4366541
project-id = 243121
`,
sha1: '478805ce54b082dadb1042ccfb46a68cfde3fc35',
sha512: '5d364049ff53af2154ccae58dd53d2111ef592b21bff03705314cd6d12378cfeb6376b8bc3065ac59e1c9452447bec0eb345ecc19f0de1a17c20ea374f802f05'
},
"waystones.pw.toml": {
type: 'file',
inline: true,
metafile: true,
content: `name = "Waystones"
filename = "waystones-forge-1.19-11.1.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/LOpKHB2A/versions/11.1.0%2Bforge-1.19/waystones-forge-1.19-11.1.0.jar"
hash-format = "sha1"
hash = "24c5403c1d5791f977a0ba69f08cf7959169c685"
[update]
[update.modrinth]
mod-id = "LOpKHB2A"
version = "2sIhirkG"
`,
sha1: '25f4b57fbd8a985b4872bb8fdadd14580b0f9f81',
sha512: '125fb6fc706363753c1c201192024415a23c1098c8e44d5deeaf5448215d83108b9a9a5aba0a029dd9015eff536dc1da63d16c3be0d7f9e39d6f482b8ce008c3'
}
} }
}
};
let blobs: Blob[] = [];
let isOpen = false;
</script> </script>
{JSON.stringify(data.session.user)} <TabGroup>
<TabList>
<Tab>Simple</Tab>
<Tab>Advanced</Tab>
</TabList>
<TabPanels>
<TabPanel>
<h1>Mods <button><PlusIcon /></button></h1>
<FlattenedFileList tree={fileTree.children.mods ?? { type: 'folder', children: {} }} />
<h1>Resource Packs <button><PlusIcon /></button></h1>
<FlattenedFileList
tree={fileTree.children.resourcepacks ?? { type: 'folder', children: {} }}
/>
<h1>Shader Packs <button><PlusIcon /></button></h1>
<FlattenedFileList tree={fileTree.children.shaderpacks ?? { type: 'folder', children: {} }} />
</TabPanel>
<TabPanel>Content 2</TabPanel>
</TabPanels>
</TabGroup>
<Dialog open={isOpen} on:close={() => (isOpen = false)}>
<DialogOverlay />
<DialogTitle>Deactivate account</DialogTitle>
<DialogDescription>This will permanently deactivate your account</DialogDescription>
<p>
Are you sure you want to deactivate your account? All of your data will be permanently removed.
This action cannot be undone.
</p>
<button on:click={() => (isOpen = false)}>Deactivate</button>
<button on:click={() => (isOpen = false)}>Cancel</button>
</Dialog>

View file

@ -3,6 +3,6 @@ import type { PageLoad } from './$types';
export const load: PageLoad = async (event) => { export const load: PageLoad = async (event) => {
const session = (await event.parent()).session; const session = (await event.parent()).session;
if (!session?.user) throw redirect(303, '/auth'); if (!session?.user) throw redirect(303, '/auth/signin');
return { session: session }; return { session: session };
}; };

View file

@ -0,0 +1,44 @@
<script lang="ts">
import type { FileTree, File } from '$lib/types';
import { metafileSchema } from '$lib/packwiz-types';
import toml from '@ltd/j-toml';
export let tree: FileTree;
function getFilesRecursively(tree: FileTree): [string[], File][] {
if (tree.type == 'file') {
return [[[], tree]];
}
let result: [string[], File][] = [];
for (const child in tree.children) {
if (Object.prototype.hasOwnProperty.call(tree.children, child)) {
const element = tree.children[child];
result = result.concat(
getFilesRecursively(element).map(([path, file]) => [[child].concat(path), file])
);
}
}
return result;
}
</script>
<ul>
{#each getFilesRecursively(tree) as mod (mod[0])}
<li>
{#if mod[1].inline && mod[1].metafile}
{@const parsed = metafileSchema.parse(toml.parse(mod[1].content))}
<h2>{parsed.name} ({mod[0].join('/')})</h2>
{#if parsed.update.curseforge}
<a
href="https://minecraft.curseforge.com/projects/{parsed.update.curseforge[
'project-id'
]}">Curseforge</a
>
{/if}
{#if parsed.update.modrinth}
<a href="https://modrinth.com/project/{parsed.update.modrinth['mod-id']}">Modrinth</a>
{/if}
{:else}
<h2>{mod[0].join('/')}</h2>
{/if}
</li>
{/each}
</ul>

View file

@ -195,6 +195,11 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@iarna/toml@^2.2.5":
version "2.2.5"
resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c"
integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==
"@jridgewell/resolve-uri@3.1.0": "@jridgewell/resolve-uri@3.1.0":
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
@ -213,6 +218,11 @@
"@jridgewell/resolve-uri" "3.1.0" "@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14" "@jridgewell/sourcemap-codec" "1.4.14"
"@ltd/j-toml@^1.38.0":
version "1.38.0"
resolved "https://registry.yarnpkg.com/@ltd/j-toml/-/j-toml-1.38.0.tgz#00d19f6d65ac5dac39bc64f97a545f47e9ebefc4"
integrity sha512-lYtBcmvHustHQtg4X7TXUu1Xa/tbLC3p2wLvgQI+fWVySguVZJF60Snxijw5EiohumxZbR10kWYFFebh1zotiw==
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -2906,11 +2916,6 @@ to-regex-range@^5.0.1:
dependencies: dependencies:
is-number "^7.0.0" is-number "^7.0.0"
toml@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==
totalist@^3.0.0: totalist@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.0.tgz#4ef9c58c5f095255cdc3ff2a0a55091c57a3a1bd" resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.0.tgz#4ef9c58c5f095255cdc3ff2a0a55091c57a3a1bd"