Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/.nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.20.2
26.3.0
4 changes: 2 additions & 2 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM node:20.20.2-alpine AS base
FROM node:26.3.0-alpine AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
WORKDIR /app
Expand All @@ -20,7 +20,7 @@ WORKDIR /app
FROM base AS deps

# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat && corepack enable && corepack prepare pnpm@8.9.0 --activate
RUN apk add --no-cache libc6-compat && npm install -g corepack && corepack enable && corepack prepare pnpm@8.9.0 --activate


# Install dependencies based on the preferred package manager root workspace
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
"devDependencies": {
"@types/js-yaml": "^4.0.5",
"@types/lodash": "^4.14.194",
"@types/node": "18.15.11",
"@types/node": "^24",
"@types/nprogress": "^0.2.0",
"@types/react": "18.0.37",
"@types/react-dom": "18.0.11"
Expand Down
14 changes: 6 additions & 8 deletions frontend/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
"immer": "^10.0.2",
"js-cookie": "^3.0.5",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"lucide-react": "^0.488.0",
Expand Down Expand Up @@ -97,26 +96,25 @@
"zustand": "^4.4.1"
},
"devDependencies": {
"@playwright/test": "^1.58.1",
"@testing-library/react": "^14.0.0",
"@types/js-cookie": "^3.0.4",
"@types/js-yaml": "^4.0.6",
"@types/jsonwebtoken": "^9.0.3",
"@types/lodash": "^4.14.199",
"@types/minio": "^7.1.1",
"@types/node": "18.15.11",
"@types/node": "^25.9.3",
"@types/nodemailer": "^6.4.15",
"@types/nprogress": "^0.2.1",
"@types/react": "18.3.27",
"@types/react-dom": "18.3.7",
"@types/umami-browser": "^2.3.2",
"@types/uuid": "^9.0.4",
"@vitejs/plugin-react": "^5.1.1",
"@vitest/browser": "4.0.15",
"@vitest/browser-playwright": "4.0.15",
"dotenv-cli": "^7.3.0",
"prettier": "^2.8.8",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.12",
"@playwright/test": "^1.58.1",
"@vitest/browser": "4.0.15",
"@vitest/browser-playwright": "4.0.15",
"@vitejs/plugin-react": "^5.1.1"
"vitest": "^4.0.12"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
generateOAuth2RefreshToken,
verifyGlobalToken
} from '@/services/backend/auth';
import { sign } from 'jsonwebtoken';
import { signJwt } from '@sealos/shared/server/jwt';

describe('verifyGlobalToken', () => {
beforeEach(() => {
Expand All @@ -31,7 +31,7 @@ describe('verifyGlobalToken', () => {
} as any);

it('maps oauth2 access token claims to legacy payload', async () => {
const token = generateOAuth2AccessToken({
const token = await generateOAuth2AccessToken({
sub: 'oauth-uid',
user_id: 'oauth-user-id',
client_id: GLOBAL_TOKEN_CLIENT_ID
Expand All @@ -46,7 +46,7 @@ describe('verifyGlobalToken', () => {
});

it('rejects oauth2 refresh token', async () => {
const token = generateOAuth2RefreshToken({
const token = await generateOAuth2RefreshToken({
sub: 'oauth-uid',
user_id: 'oauth-user-id',
client_id: GLOBAL_TOKEN_CLIENT_ID
Expand All @@ -58,7 +58,7 @@ describe('verifyGlobalToken', () => {
});

it('rejects oauth2 access token without subject', async () => {
const token = sign(
const token = await signJwt(
{
client_id: GLOBAL_TOKEN_CLIENT_ID,
token_type: 'access_token',
Expand All @@ -74,7 +74,7 @@ describe('verifyGlobalToken', () => {
});

it('rejects oauth2 access token without user_id', async () => {
const token = sign(
const token = await signJwt(
{
sub: 'oauth-uid',
client_id: GLOBAL_TOKEN_CLIENT_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: session.userUid,
userId: session.userId
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: session.userUid,
userId: session.userId
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: session.userUid,
userId: session.userId
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: session.userUid,
userId: session.userId
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ async function handlePost(

const data = validationResult.data;

const globalToken = generateLegacyGlobalToken({
const globalToken = await generateLegacyGlobalToken({
userUid: payload.userUid,
userId: payload.userId,
regionUid: payload.regionUid
Expand Down Expand Up @@ -346,7 +346,7 @@ async function handleGetBanks(
const config: UnionPay3060Config = realNameAuthProvider.config as UnionPay3060Config;
const enterpriseRealNameAuthApi = config.api;

const globalToken = generateLegacyGlobalToken({
const globalToken = await generateLegacyGlobalToken({
userUid: payload.userUid,
userId: payload.userId,
regionUid: payload.regionUid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
global.AppConfig?.common.realNameCallbackUrl ||
`https://${global.AppConfig?.cloud.domain}/api/account/faceIdRealNameAuthCallback`;

const globalToken = generateLegacyGlobalToken(
const globalToken = await generateLegacyGlobalToken(
{
userUid: payload.userUid,
userId: payload.userId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
global.AppConfig?.common.realNameCallbackUrl ||
`https://${global.AppConfig?.cloud.domain}/api/account/faceIdRealNameAuthCallback`;

const globalToken = generateLegacyGlobalToken(
const globalToken = await generateLegacyGlobalToken(
{
userUid: payload.userUid,
userId: payload.userId
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/src/pages/api/auth/globalToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
code: 200,
message: 'Successfully',
data: {
token: generateGlobalAccessToken({
token: await generateGlobalAccessToken({
sub: regionUserData.userUid,
user_id: regionUserData.userId
})
Expand Down
4 changes: 2 additions & 2 deletions frontend/desktop/src/pages/api/auth/namespace/switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
userId: payload.userId,
userUid: payload.userUid
};
const token = generateRegionalToken(jwtPayload);
const appToken = generateAppToken(jwtPayload);
const token = await generateRegionalToken(jwtPayload);
const appToken = await generateAppToken(jwtPayload);
const data = {
token,
appToken
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/src/pages/api/desktop/getBilling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

const base = global.AppConfig.desktop.auth.billingUrl as string;
const consumptionUrl = base + '/account/v1alpha1/costs/all-region-consumption';
const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: payload.userUid,
userId: payload.userId
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/src/pages/api/plan/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: payload.userUid,
userId: payload.userId
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/src/pages/api/plan/workspaces-plans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: payload.userUid,
userId: payload.userId
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/src/pages/api/workspace/getQuota.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return jsonRes(res, { code: 500, message: 'Billing service not configured' });
}

const billingToken = generateBillingToken({
const billingToken = await generateBillingToken({
userUid: session.userUid,
userId: session.userId
});
Expand Down
34 changes: 13 additions & 21 deletions frontend/desktop/src/services/backend/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
OAuth2RefreshTokenPayload,
OnceTokenPayload
} from '@/types/token';
import { signJwt, verifyJwt as verifySharedJwt } from '@sealos/shared/server/jwt';
import { IncomingHttpHeaders } from 'http';
import { sign, verify } from 'jsonwebtoken';

const regionUID = () => global.AppConfig?.cloud.regionUID || '123456789';
export const globalJwtSecret = () => global.AppConfig?.desktop.auth.jwt.global || '123456789';
Expand Down Expand Up @@ -129,19 +129,11 @@ export const verifyGlobalToken = async (
return null;
};

const signPayload = <T extends object>(payload: T, secret: string, expiresIn: string) =>
signJwt(payload as Record<string, unknown>, secret, { expiresIn });

const verifyJwt = <T extends object = JWTPayload>(token: string | undefined, secret: string) =>
new Promise<T | null>((resolve) => {
if (!token) return resolve(null);
verify(token, secret, (err, payload) => {
if (err) {
resolve(null);
} else if (!payload) {
resolve(null);
} else {
resolve(payload as T);
}
});
});
verifySharedJwt(token, secret) as Promise<T | null>;

export const verifyRegionalJwt = <T extends object = JWTPayload>(token?: string) =>
verifyJwt<T>(token, regionalJwtSecret());
Expand All @@ -160,13 +152,13 @@ export const verifyAppToken = async (header: IncomingHttpHeaders) => {
};

export const generateBillingToken = (props: BillingTokenPayload) =>
sign(props, internalJwtSecret(), { expiresIn: '3600000' });
signPayload(props, internalJwtSecret(), '3600000');

export const generateRegionalToken = (props: AccessTokenPayload) =>
sign(props, regionalJwtSecret(), { expiresIn: '7d' });
signPayload(props, regionalJwtSecret(), '7d');

export const generateAppToken = (props: AccessTokenPayload) =>
sign(props, internalJwtSecret(), { expiresIn: '7d' });
signPayload(props, internalJwtSecret(), '7d');

/**
* Signs global token.
Expand All @@ -182,7 +174,7 @@ export const signGlobalToken = (props: GlobalJwtClaims, expiresIn?: string) => {
...props
};

return sign(payload, globalJwtSecret(), { expiresIn: expiresIn ?? '7d' });
return signPayload(payload, globalJwtSecret(), expiresIn ?? '7d');
};

/**
Expand All @@ -199,7 +191,7 @@ export const generateLegacyGlobalToken = (props: GlobalTokenPayload, expiresIn?:
// [FIXME] Should have a client_id in here but external services will reject the additional claim.
};

return sign(payload, globalJwtSecret(), { expiresIn: expiresIn ?? '7d' });
return signPayload(payload, globalJwtSecret(), expiresIn ?? '7d');
};

/**
Expand Down Expand Up @@ -267,10 +259,10 @@ export const verifyOAuth2RefreshToken = (token?: string) =>
verifyOAuth2TokenByType(token, REFRESH_TOKEN_TYPE);

export const generateOnceToken = (props: OnceTokenPayload) =>
sign(props, regionalJwtSecret(), { expiresIn: '1800000' });
signPayload(props, regionalJwtSecret(), '1800000');

export const generateCronJobToken = (props: CronJobTokenPayload) =>
sign(props, internalJwtSecret(), { expiresIn: '60000' });
signPayload(props, internalJwtSecret(), '60000');

export const callBillingService = async (
endpoint: string,
Expand All @@ -282,7 +274,7 @@ export const callBillingService = async (
throw new Error('Billing service not configured');
}

const billingToken = generateBillingToken(payload);
const billingToken = await generateBillingToken(payload);
const regionDomain = body.regionDomain || global.AppConfig.cloud.domain;
const requestBody = {
...body,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,21 +264,21 @@ export class MergeUserCrJob implements CronJobStatus {
headers: {
Authorization:
'Bearer ' +
generateBillingToken({
(await generateBillingToken({
userUid: mergeUser.uid,
userId: mergeUser.id
})
}))
}
}
),
axios.post(workorderUrl, {
token: generateCronJobToken({
token: await generateCronJobToken({
userUid: user.id,
mergeUserUid: mergeUser.id
})
}),
axios.post(cvmUrl, {
token: generateCronJobToken({
token: await generateCronJobToken({
userUid: user.uid,
mergeUserUid: mergeUser.uid
})
Expand Down
2 changes: 1 addition & 1 deletion frontend/desktop/src/services/backend/globalAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ export const getGlobalToken = async ({

// user is deleted or banned
if (user.status !== UserStatus.NORMAL_USER) return null;
const token = generateGlobalAccessToken({
const token = await generateGlobalAccessToken({
sub: user.uid,
user_id: user.id,
preferred_username: user.nickname
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@ export const otherRegionResourceGuard =
(region) => region.uid !== global.AppConfig.cloud.regionUID
);
const otherCheckResp = await Promise.all(
regionTarget.map((region) =>
regionTarget.map(async (region) =>
fetch(
process.env.NODE_ENV === 'development'
? `http://127.0.0.1:3000/api/auth/delete/checkResource`
: `https://${region.domain}/api/auth/delete/checkResource`,
{
headers: {
authorization: encodeURI(
generateLegacyGlobalToken({
await generateLegacyGlobalToken({
userUid: userUid,
userId: userId
})
Expand Down
Loading
Loading