Skip to content

Commit

Permalink
feat: user-attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
lisonge committed Jun 17, 2024
1 parent f661775 commit 123d6c6
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 121 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"typescript": "5.4.5",
"universal-base64url": "1.1.0",
"unocss": "0.59.3",
"user-attachments": "1.1.1",
"vite": "5.2.9",
"vite-plugin-monkey": "3.5.2",
"vue": "3.4.23",
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions src/components/BuildShareDlg.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="tsx">
import { uploadPoliciesAssets } from '@/utils/github';
import { uploadAsset } from '@/utils/github';
import { copy } from '@/utils/others';
import { useTask } from '@/utils/task';
import { useDebounceFn } from '@vueuse/core';
Expand Down Expand Up @@ -51,7 +51,7 @@ const copyLink = () => {
const buildShare = useTask(async () => {
const data = JSON5.parse(text.value);
const asset = await uploadPoliciesAssets(
const asset = await uploadAsset(
new TextEncoder().encode(
JSON5.stringify({
data,
Expand All @@ -60,7 +60,6 @@ const buildShare = useTask(async () => {
}),
),
'file.txt',
'text/plain',
);
const link = location.origin + router.resolve(`/s/${asset.id}`).href;
shareLink.value = link;
Expand Down
8 changes: 3 additions & 5 deletions src/utils/export.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { saveAs } from 'file-saver';
import JSZip from 'jszip';
import pLimit from 'p-limit';
import { uploadPoliciesAssets } from './github';
import { uploadAsset } from './github';
import { delay } from './others';
import {
githubJpgStorage,
Expand Down Expand Up @@ -81,10 +81,9 @@ export const batchZipDownloadZip = async (snapshots: Snapshot[]) => {
export const exportSnapshotAsJpgUrl = async (snapshot: Snapshot) => {
return (
githubJpgStorage[snapshot.id] ??
uploadPoliciesAssets(
uploadAsset(
await snapshotAsJpg(snapshot).then((r) => r.arrayBuffer()),
'file.jpg',
'image/jpeg',
).then((r) => {
githubJpgStorage[snapshot.id] = r.href;
return r.href;
Expand All @@ -95,10 +94,9 @@ export const exportSnapshotAsJpgUrl = async (snapshot: Snapshot) => {
export const exportSnapshotAsImportId = async (snapshot: Snapshot) => {
return (
importStorage[snapshot.id] ||
uploadPoliciesAssets(
uploadAsset(
await snapshotAsZip(snapshot).then((r) => r.arrayBuffer()),
'file.zip',
'application/x-zip-compressed',
).then((r) => {
importStorage[snapshot.id] = r.id;
urlStorage[r.id] = snapshot.id;
Expand Down
126 changes: 13 additions & 113 deletions src/utils/github.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,22 @@
import { enhanceFetch } from './fetch';
import { obj2form } from './others';
import store from './store';
import { uploadPoliciesAssets } from 'user-attachments';
import type { PoliciesAsset } from 'user-attachments';

const authenticityTokenPageUrl = `https://github.com/gkd-kit/inspect/issues/new`;
const repository_id = `661952005`;
const commonHeaders = {
origin: `https://github.com`,
referer: authenticityTokenPageUrl,
};

const getCsrfToken = async () => {
const csrfSelector = `[data-upload-policy-url="/upload/policies/assets"] input.js-data-upload-policy-url-csrf`;
const resp = await enhanceFetch(authenticityTokenPageUrl);
const responseDoc = new DOMParser().parseFromString(
await resp.text(),
'text/html',
);
const csrfToken = responseDoc
.querySelector(csrfSelector)
?.getAttribute(`value`);
return csrfToken;
};

type S3Form = {
key: string;
acl: string;
policy: string;
'X-Amz-Algorithm': string;
'X-Amz-Credential': string;
'X-Amz-Date': string;
'X-Amz-Signature': string;
'Content-Type': string;
'Cache-Control': string;
'x-amz-meta-Surrogate-Control': string;
};
export type GithubPoliciesAsset = {
id: number;
name: string;
size: number;
content_type: string;
original_name: string;
href: string;
};

type UploadPoliciesAssetsRsonpse = {
upload_url: string;
header: object;
asset: GithubPoliciesAsset;
form: S3Form;
same_origin: boolean;
asset_upload_url: string;
upload_authenticity_token: string;
asset_upload_authenticity_token: string;
};
export type GithubPoliciesAsset = PoliciesAsset;

export const uploadPoliciesAssets = async (
export const uploadAsset = async (
bf: ArrayBuffer,
name: string,
content_type: string,
): Promise<GithubPoliciesAsset> => {
const authenticity_token = await getCsrfToken();
if (!authenticity_token) {
store.githubErrorDlgVisible = true;
throw new Error(`failed get csrfToken`);
}

const policiesResp: UploadPoliciesAssetsRsonpse = await enhanceFetch(
`https://github.com/upload/policies/assets`,
{
method: `POST`,
body: obj2form({
authenticity_token,
content_type,
name,
size: bf.byteLength,
repository_id,
}),
headers: commonHeaders,
},
).then((r) => {
if (!r.ok) {
throw new Error(`failed upload policies assets`);
): Promise<PoliciesAsset> => {
return await uploadPoliciesAssets({
file: new File([bf], name),
url: 'https://github.com/gkd-kit/inspect/issues/1',
fetch: enhanceFetch,
}).catch((e) => {
if (e instanceof Error && e.message === 'not found authenticity_token') {
store.githubErrorDlgVisible = true;
}
return r.json();
});

// violentmonkey success
// tampermonkey failed https://github.com/Tampermonkey/tampermonkey/issues/1783
// use fetch is also work, but console.error cors and can not get response
const s3Resp = await enhanceFetch(policiesResp.upload_url, {
method: `POST`,
body: obj2form(policiesResp.form, {
file: new File([bf], name, { type: content_type }),
}),
headers: commonHeaders,
throw e;
});
if (!s3Resp.ok) {
throw new Error(`upload s3 failed`);
}

const assetsResp = await enhanceFetch(
new URL(policiesResp.asset_upload_url, `https://github.com/`).href,
{
method: `PUT`,
body: obj2form({
authenticity_token: policiesResp.asset_upload_authenticity_token,
}),
headers: {
...commonHeaders,
// api must add `Accept` request headers
Accept: `application/json`,
},
},
);

if (assetsResp.status != 200) {
throw new Error(`failed check authenticity upload`);
}

return policiesResp.asset;
};

0 comments on commit 123d6c6

Please sign in to comment.