Compare commits

...

5 Commits

Author SHA1 Message Date
2527056e85 Get Beta builds & beta docker compose stuff. 2025-06-10 16:38:29 +08:00
801df6fdca Update translations & testing in prod again. 2025-06-10 16:35:28 +08:00
78bead88cf Add translations into the login system (Also commiting the settings
window to test in prod)
2025-06-10 16:23:55 +08:00
af92b7c573 Nuke user metadata. 2025-06-10 14:46:12 +08:00
2895263e52 Add getUserTokenMinusSQLInjection to prevent SQL Injection in via the
cookies (that may be not possible, but it is a safety guard I want to
add. (Chat: https://t3.chat/chat/c1883e6a-6c38-4af3-9818-0e927449c61c)
2025-06-10 09:39:11 +08:00
15 changed files with 236 additions and 61 deletions

View File

@ -0,0 +1,54 @@
name: Build and Push Docker Image
on:
push:
branches:
- beta
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=beta
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha,prefix=
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@ -4,9 +4,6 @@ on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
env:
@ -37,6 +34,7 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}

View File

@ -168,9 +168,11 @@ const jaccardSimilarity = (v1: any, v2: any) => {
return intersection.size / union.size;
};
const findRel = async (title: string) => {
/*
const findRel =
async (title: string) => {
const req = await fetch("/api/sort");
};
};*/
// Check words
const checkIfEmptyArray = [];

View File

@ -99,6 +99,8 @@ const deleteAccount = async () => {
const req = await fetch("/api/user/sendUserChanges", {
method: "DELETE",
});
const res = await res.json();
console.log(res);
};
const submitChangeAction = async (action: string) => {
@ -172,7 +174,42 @@ const submitUserPassword = async () => {
};
</script>
<template>
<div class="justify-center align-center text-center">
<div
class="justify-center align-center text-center absloute inset-0 p-1"
v-if="!isLoggedIn"
>
<form
class="flex flex-col items-center justify-center h-full"
@submit.prevent="submitUserPassword"
v-if="!success"
>
<span class="text-2xl text-bold mb-0">{{ t("settings.login") }}</span>
<span class="mb-4 text-sm mt-0"> {{ t("settings.loginmessage") }}</span>
<div class="">
<Input
type="text"
:placeholder="t('settings.placeholder.user')"
class="mb-2 p-2 border rounded"
v-model="userAccount"
required
/>
<Input
type="password"
:placeholder="t('settings.placeholder.password')"
class="p-2 border rounded mb-2"
v-model="userPassword"
required
/>
</div>
<span v-if="error" class="text-red-600 text-xs m-2"
>Error: {{ errormsg }}</span
>
<button class="bg-black text-white p-2 rounded transition duration-200">
{{ t("settings.loginButton") }}
</button>
</form>
</div>
<div class="justify-center align-center text-center" v-if="isLoggedIn">
<h1 class="text-3xl text-bold p-2">
{{ t("settings.greet")
}}{{ user || userData.userAccount || t("settings.defaultname") }}

33
docker-compose-beta.yml Executable file
View File

@ -0,0 +1,33 @@
services:
reverse-proxy:
image: traefik:v3.1
command:
- "--providers.docker"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
ports:
- 127.0.0.1:36694:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- web
newsanalyze-service:
image: ghcr.io/hpware/news-analyze:beta
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.newsanalyze.rule=Host(`news.yuanhau.com`)"
- "traefik.http.services.newsanalyze.loadbalancer.server.port=3000"
- "com.centurylinklabs.watchtower.enable=true"
restart: unless-stopped
env_file:
- path: ./.env
required: true
deploy:
mode: replicated
replicas: 2
networks:
web:

View File

@ -13,7 +13,7 @@ services:
- web
newsanalyze-service:
image: ghcr.io/hpware/news-analyze:master
image: ghcr.io/hpware/news-analyze:latest
networks:
- web
labels:

View File

@ -86,7 +86,14 @@
"dangerzone": "DANGER ZONE",
"submit": "Submit",
"greet": "Greetings, ",
"defaultname": "User"
"defaultname": "User",
"login": "Login / Register",
"loginmessage": "We will create a account for you if you don't have one.",
"loginButton": "Log In",
"placeholder": {
"user": "Username",
"password": "Password"
}
},
"popuptext": {
"logout": "Are you sure you want to logout?",
@ -138,7 +145,7 @@
"opennewwindow": "This will open a new window",
"similararticles": "Similar Articles",
"similarity": "Similarity",
"nosimilararticles": "There isn't any similar articles.",
"nosimilararticles": "There aren't any similar articles.",
"articleopenpart1": "This will open a open a new window about this new org",
"articleopenpart2": ""
}

View File

@ -86,7 +86,14 @@
"dangerzone": "DANGER ZONE",
"submit": "送出",
"greet": "嗨, ",
"defaultname": "使用者"
"defaultname": "使用者",
"login": "登入 / 註冊",
"loginmessage": "如果妳沒有帳號的話,我們會幫你註冊一個。",
"loginButton": "登入按鈕",
"placeholder": {
"user": "使用者帳號",
"password": "密碼"
}
},
"popup": {
"cancel": "取消",

View File

@ -1 +0,0 @@
export default defineEventHandler(async (event) => {});

View File

@ -1,15 +1,16 @@
import getUserTokenMinusSQLInjection from "~/server/components/getUserToken";
export default defineEventHandler(async (event) => {
const loginCookie = getCookie(event, "session");
const lastCheckCookie = getCookie(event, "last_check");
const nowDate = new Date().toLocaleString();
const loginCookie = await getUserTokenMinusSQLInjection(event);
try {
if (loginCookie) {
if (false) {
deleteCookie(event, "token");
return {
success: true,
error: null,
};
}
return "testing";
} catch (e) {
return {
success: false,

View File

@ -1,6 +1,39 @@
import sql from "~/server/components/postgres";
import getUserTokenMinusSQLInjection from "~/server/components/getUserToken";
export default defineEventHandler(async (event) => {
const userToken = getCookie(event, "token");
return {
token: userToken,
};
try {
const userToken = await getUserTokenMinusSQLInjection(event);
if (userToken.error.length !== 0) {
return {
error: userToken.error,
};
}
// REMOVE OLD TOKENS
const removeToken = await sql`
DELETE FROM usertokens
WHERE username = ${userToken.user}
`;
console.log(removeToken);
// DELETE USER
const deleteUserAccount = await sql`
DELETE FROM users
WHERE username = ${userToken.user}
`;
const deleteOtherUserMetaData = await sql`
DELETE FROM user_other_data
WHERE username = ${userToken.user}
`;
console.log(deleteUserAccount);
console.log(deleteOtherUserMetaData);
deleteCookie(event, "token");
return {
success: true,
};
} catch (e) {
console.log(e);
return {
error: "INTERNAL_SERVER_ERROR",
e: e.message,
};
}
});

View File

@ -1,17 +1,9 @@
import sql from "~/server/components/postgres";
import getUserTokenMinusSQLInjection from "~/server/components/getUserToken";
export default defineEventHandler(async (event) => {
// Check user data.
const userToken = getCookie(event, "token");
if (!userToken) {
return {
error: "ERR_NOT_ALLOWED",
};
}
const checkUserToken = await sql`
select * from usertokens
where token=${userToken}
`;
if (checkUserToken.length === 0) {
const token = await getUserTokenMinusSQLInjection(event);
if (token.error.length !== 0) {
return {
error: "ERR_NOT_ALLOWED",
};
@ -37,26 +29,11 @@ export default defineEventHandler(async (event) => {
`
UPDATE user_other_data SET ${requestChange} = $1
WHERE username = $2`,
[apiKeyqq[0], checkUserToken[0].username],
[apiKeyqq[0], token.user],
);
/**
* // Example of how requestChange might be validated
const allowedColumns = ['groq_api_key', 'another_column_name'];
if (!allowedColumns.includes(requestChange)) {
throw new Error('Invalid column name provided');
}
const sqlC = await sql`
UPDATE user_other_data SET ${sql.identifier([requestChange])} = ${apiKeyqq[0]}
WHERE username = ${checkUserToken[0].username}`;
*/
return {
body: body,
allowed: allowed,
data: body.value.match(clearBadDataRegex),
sqlC: sqlC,
success: true,
};
}
});

View File

@ -1,19 +1,11 @@
import sql from "~/server/components/postgres";
import getUserTokenMinusSQLInjection from "~/server/components/getUserToken";
export default defineEventHandler(async (event) => {
// Check user data.
const userToken = getCookie(event, "token");
if (!userToken) {
const user = getUserTokenMinusSQLInjection(event);
if (user.error.length !== 0) {
return {
error: "ERR_NOT_ALLOWED",
};
}
const checkUserToken = await sql`
select * from usertokens
where token=${userToken}
`;
if (checkUserToken.length === 0) {
return {
error: "ERR_NOT_ALLOWED",
error: user.error,
};
}
// Actual function
@ -26,7 +18,7 @@ export default defineEventHandler(async (event) => {
`
UPDATE user_other_data SET ${requestChange} = $1
WHERE username = $2`,
[apiKeyqq[0], checkUserToken[0].username],
[apiKeyqq[0], user.user],
);
return {
body: body,

View File

@ -0,0 +1,35 @@
import sql from "~/server/components/postgres";
export default async function getUserTokenMinusSQLInjection(event) {
const userToken = await getCookie(event, "token");
if (!userToken) {
return {
token: null,
user: null,
error: "NO_TOKEN",
};
}
const uuidRegex =
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
if (!uuidRegex.test(userToken)) {
return {
token: null,
user: null,
error: "INVALID_TOKEN_FORMAT",
};
}
const getUser = await sql`
select * from usertokens
where token = ${userToken}`;
if (getUser.length === 0) {
return {
token: null,
user: null,
error: "NOT_AUTHED",
};
}
return {
token: userToken,
user: getUser[0].username,
error: "",
};
}

View File

@ -17,7 +17,7 @@ And also I wrote a super stupid cron fix, which is below.
## My stupid cron fix:
Cron Job:
```
0 1 * * * "bun run /hardpushrevolvconf.ts" > /dev/null
0 * * * * "bun run /hardpushrevolvconf.ts" > /dev/null
```
Here is the script I used to force the change of my resolv.conf file: