Skip to content
Permalink
75402b3315
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
300 lines (272 sloc) 7.61 KB
function arrBufToB64Url(buf: ArrayBuffer) {
const b64data = btoa(String.fromCharCode(...new Uint8Array(buf)));
return b64data.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
function stringToBuffer(str: string) {
const buffer = new ArrayBuffer(str.length);
const ui8 = new Uint8Array(buffer);
for (let i = 0, bufLen = str.length; i < bufLen; i++) {
ui8[i] = str.charCodeAt(i);
}
return buffer;
}
export async function GenerateUploadURL(
env: Env,
path: string,
size: number,
fileExt: string,
origin: string,
): Promise<string> {
const accessToken = await GetAccessToken(env);
const contentTypes: { [k: string]: string } = {
gif: "image/gif",
m4v: "video/x-m4v",
mkv: "video/x-matroska",
mov: "video/mp4",
mp4: "video/mp4",
webm: "video/webm",
wmv: "video/x-ms-wmv",
};
const resumableUploadReq = await fetch(
`https://storage.googleapis.com/upload/storage/v1/b/portal-carcrushers-cc/o?uploadType=resumable&name=${encodeURIComponent(
path,
)}`,
{
headers: {
authorization: `Bearer ${accessToken}`,
origin,
"x-upload-content-type": contentTypes[fileExt],
"x-upload-content-length": size.toString(),
},
method: "POST",
},
);
if (!resumableUploadReq.ok)
throw new Error(
`Failed to create resumable upload: ${await resumableUploadReq.text()}`,
);
const url = resumableUploadReq.headers.get("location");
if (!url) throw new Error("No location header returned");
return url;
}
export async function GetAccessToken(env: Env): Promise<string> {
const claimSet = btoa(
JSON.stringify({
aud: "https://oauth2.googleapis.com/token",
exp: Math.floor(Date.now() / 1000) + 120,
iat: Math.floor(Date.now() / 1000),
iss: env.WORKER_GSERVICEACCOUNT,
scope: "https://www.googleapis.com/auth/cloud-platform",
}),
)
.replaceAll("+", "-")
.replaceAll("/", "_")
.replaceAll("=", "");
const signingKey = await crypto.subtle.importKey(
"pkcs8",
stringToBuffer(atob(env.STORAGE_ACCOUNT_KEY.replace(/(\r\n|\n|\r)/gm, ""))),
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
false,
["sign"],
);
const signature = await crypto.subtle.sign(
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
signingKey,
stringToBuffer(`eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.${claimSet}`),
);
const assertion = `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.${claimSet}.${arrBufToB64Url(
signature,
)}`;
const tokenRequest = await fetch("https://oauth2.googleapis.com/token", {
body: `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${assertion}`,
headers: {
"content-type": "application/x-www-form-urlencoded",
},
method: "POST",
});
if (!tokenRequest.ok)
throw new Error(`Failed to get access token: ${await tokenRequest.text()}`);
return ((await tokenRequest.json()) as { [k: string]: any }).access_token;
}
async function getKeyIDs(
access_token: string,
projectId: string,
keys: { partitionId: { projectId: string }; path: { kind: string }[] }[],
) {
const keyRequest = await fetch(
`https://datastore.googleapis.com/v1/projects/${projectId}:allocateIds`,
{
body: JSON.stringify({ keys }),
headers: {
authorization: `Bearer ${access_token}`,
"content-type": "application/json",
},
method: "POST",
},
);
if (!keyRequest.ok) {
console.log(await keyRequest.json());
throw new Error("Failed to allocate key IDs");
}
return ((await keyRequest.json()) as { keys: { [k: string]: any }[] }).keys;
}
export async function insertLogs(
userActionMap: { [k: string]: number },
reportId: string,
context: RequestContext,
) {
const accessToken = await GetAccessToken(context.env);
const actionBaseURLs: { [k: number]: string } = {
1: "https://portal.carcrushers.cc/view-closed-report/",
2: "https://portal.carcrushers.cc/view-closed-report/",
3: "",
4: "https://portal.carcrushers.cc/game-appeals/",
};
const actionIntegers: { [k: number]: string } = {
1: "blacklist",
2: "ban",
3: "revoke",
4: "accept_appeal",
};
const incompleteLogKey = {
partitionId: {
projectId: context.env.DATASTORE_PROJECT,
},
path: [
{
kind: "log",
},
],
};
const payload: { mode: string; mutations: { [k: string]: any }[] } = {
mode: "NON_TRANSACTIONAL",
mutations: [],
};
const preAllocatedLogKeys = [];
while (preAllocatedLogKeys.length < Object.keys(userActionMap).length)
preAllocatedLogKeys.push(incompleteLogKey);
const keys = await getKeyIDs(
accessToken,
context.env.DATASTORE_PROJECT,
preAllocatedLogKeys,
);
for (const [user, action] of Object.entries(userActionMap)) {
payload.mutations.push({
insert: {
key: keys.pop(),
properties: {
action: {
stringValue: actionIntegers[action],
},
evidence: {
stringValue: actionBaseURLs[action] + reportId,
},
executed_at: {
integerValue: Date.now(),
},
executor: {
stringValue: context.data.current_user.id,
},
target: {
integerValue: user,
},
},
},
});
}
const mutationRequest = await fetch(
`https://datastore.googleapis.com/v1/projects/${context.env.DATASTORE_PROJECT}:commit`,
{
body: JSON.stringify(payload),
headers: {
authorization: `Bearer ${accessToken}`,
"content-type": "application/json",
},
method: "POST",
},
);
if (!mutationRequest.ok) {
console.log(await mutationRequest.json());
throw new Error("Failed to commit mutation");
}
return await mutationRequest.json();
}
export async function queryLogs(user: number, context: RequestContext) {
const accessToken = await GetAccessToken(context.env);
const queryRequest = await fetch(
`https://datastore.googleapis.com/v1/projects/${context.env.DATASTORE_PROJECT}:runQuery`,
{
body: JSON.stringify({
partitionId: {
projectId: context.env.DATASTORE_PROJECT,
},
query: {
filter: {
propertyFilter: {
op: "EQUAL",
property: {
name: "target",
},
value: {
integerValue: user.toString(),
},
},
},
kind: [
{
name: "log",
},
],
},
}),
headers: {
authorization: `Bearer ${accessToken}`,
"content-type": "application/json",
},
method: "POST",
},
);
if (!queryRequest.ok) {
console.log(await queryRequest.json());
throw new Error("Failed to query logs");
}
return (
(
(await queryRequest.json()) as {
batch: {
entityResults: {
cursor: string;
entity: { [k: string]: any };
version: string;
}[];
};
}
).batch?.entityResults ?? []
);
}
export async function sendPushNotification(
env: Env,
title: string,
body: string,
token?: string,
) {
const message = {
notification: {
body,
title,
},
token,
};
const notifResp = await fetch(
"https://fcm.googleapis.com/v1/projects/car-crushers-mobile/messages:send",
{
body: JSON.stringify({ message }),
headers: {
authorization: `Bearer ${await GetAccessToken(env)}`,
"content-type": "application/json",
},
method: "POST",
},
);
if (!notifResp.ok) throw new Error(await notifResp.text());
}