mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor(gitlab): add refresh token validation
This commit is contained in:
parent
6d945371c9
commit
a8408a11d9
1
apps/dokploy/drizzle/0046_wonderful_oracle.sql
Normal file
1
apps/dokploy/drizzle/0046_wonderful_oracle.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "gitlab_provider" ADD COLUMN "expires_at" integer;
|
3455
apps/dokploy/drizzle/meta/0046_snapshot.json
Normal file
3455
apps/dokploy/drizzle/meta/0046_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -323,6 +323,13 @@
|
|||||||
"when": 1725162377005,
|
"when": 1725162377005,
|
||||||
"tag": "0045_dazzling_liz_osborn",
|
"tag": "0045_dazzling_liz_osborn",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 46,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1725168434474,
|
||||||
|
"tag": "0046_wonderful_oracle",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -36,45 +36,12 @@ export default async function handler(
|
|||||||
if (!result.access_token || !result.refresh_token) {
|
if (!result.access_token || !result.refresh_token) {
|
||||||
return res.status(400).json({ error: "Missing or invalid code" });
|
return res.status(400).json({ error: "Missing or invalid code" });
|
||||||
}
|
}
|
||||||
|
const expiresAt = Math.floor(Date.now() / 1000) + result.expires_in;
|
||||||
const updatedGiltab = await updateGitlabProvider(gitlab.gitlabProviderId, {
|
const updatedGiltab = await updateGitlabProvider(gitlab.gitlabProviderId, {
|
||||||
accessToken: result.access_token,
|
accessToken: result.access_token,
|
||||||
refreshToken: result.refresh_token,
|
refreshToken: result.refresh_token,
|
||||||
|
expiresAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.redirect(307, "/dashboard/settings/git-providers");
|
return res.redirect(307, "/dashboard/settings/git-providers");
|
||||||
}
|
}
|
||||||
// b7262a56a0e84690d6352e07147e0cc4ff862818efe93a5fc7a12dc99a1382fd
|
|
||||||
// {
|
|
||||||
// accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
||||||
// host: 'localhost:3000',
|
|
||||||
// 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
|
|
||||||
// 'accept-encoding': 'gzip, deflate, br, zstd',
|
|
||||||
// 'accept-language': 'es-ES,es;q=0.9',
|
|
||||||
// 'cache-control': 'max-age=0',
|
|
||||||
// referer: 'https://gitlab.com/',
|
|
||||||
// 'x-request-id': '3e925ffc549f9a3d3ef5d5f376c2a6f0',
|
|
||||||
// 'x-real-ip': '10.240.3.64',
|
|
||||||
// 'x-forwarded-port': '443',
|
|
||||||
// 'x-forwarded-scheme': 'https',
|
|
||||||
// 'x-original-uri': '/api/providers/gitlab/callback?code=f26181b5c7397444ace5211f9ac4683b2d7bd64cd9431e85d3b6b4722827fabf',
|
|
||||||
// 'x-scheme': 'https',
|
|
||||||
// 'sec-fetch-site': 'cross-site',
|
|
||||||
// 'sec-fetch-mode': 'navigate',
|
|
||||||
// 'sec-fetch-user': '?1',
|
|
||||||
// 'sec-fetch-dest': 'document',
|
|
||||||
// 'sec-ch-ua': '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
|
|
||||||
// 'sec-ch-ua-mobile': '?0',
|
|
||||||
// 'sec-ch-ua-platform': '"macOS"',
|
|
||||||
// priority: 'u=0, i',
|
|
||||||
// 'x-original-proto': 'https',
|
|
||||||
// cookie: 'rl_anonymous_id=RS_ENC_v3_IjEzMzVhYzg0LTIyYjctNGExNi04YzE5LTg4M2ZiOTEwMTRmYSI%3D; rl_page_init_referrer=RS_ENC_v3_IiRkaXJlY3Qi; __adroll_fpc=7113966cdd8d59aba5e5ef62ff22c535-1715634343969; rl_session=RS_ENC_v3_eyJpZCI6MTcxNTYzNDM0Mzc1NiwiZXhwaXJlc0F0IjoxNzE1NjM3MDY5NDg1LCJ0aW1lb3V0IjoxODAwMDAwLCJhdXRvVHJhY2siOnRydWV9; _ga_65LBX6LVJK=GS1.1.1715634344.1.1.1715635269.0.0.0; __ar_v4=FZBVRO7FTNEL3NZLTQLETP%3A20240512%3A9%7CJTXM2THZSJHDPEH4IPCBUU%3A20240512%3A9%7CFPP3PVDSUZBVHNEE67AUWV%3A20240512%3A9; auth_session=ih5fycwxzb5qkubabuc7u4qvz3wn2cfjzjdnigdh',
|
|
||||||
// 'x-forwarded-proto': 'https',
|
|
||||||
// 'x-forwarded-host': 'mcnknfld-3000.use2.devtunnels.ms',
|
|
||||||
// 'x-forwarded-for': '10.240.3.64',
|
|
||||||
// 'proxy-connection': 'Keep-Alive',
|
|
||||||
// 'x-middleware-invoke': '',
|
|
||||||
// 'x-invoke-path': '/api/providers/gitlab/callback',
|
|
||||||
// 'x-invoke-query': '%7B%22code%22%3A%22f26181b5c7397444ace5211f9ac4683b2d7bd64cd9431e85d3b6b4722827fabf%22%2C%22__nextDefaultLocale%22%3A%22en%22%2C%22__nextLocale%22%3A%22en%22%7D',
|
|
||||||
// 'x-invoke-output': '/api/providers/gitlab/callback'
|
|
||||||
// }
|
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
haveGithubRequirements,
|
haveGithubRequirements,
|
||||||
haveGitlabRequirements,
|
haveGitlabRequirements,
|
||||||
removeGithubProvider,
|
removeGithubProvider,
|
||||||
|
updateGitlabProvider,
|
||||||
} from "../services/git-provider";
|
} from "../services/git-provider";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@ -125,6 +126,8 @@ export const gitProvider = createTRPCRouter({
|
|||||||
if (!input.gitlabProviderId) {
|
if (!input.gitlabProviderId) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
await refreshGitlabToken(input.gitlabProviderId);
|
||||||
|
|
||||||
const gitlabProvider = await getGitlabProvider(input.gitlabProviderId);
|
const gitlabProvider = await getGitlabProvider(input.gitlabProviderId);
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://gitlab.com/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`,
|
`https://gitlab.com/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`,
|
||||||
@ -161,16 +164,18 @@ export const gitProvider = createTRPCRouter({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
if (!input.gitlabProviderId) {
|
console.log(input);
|
||||||
|
if (!input.gitlabProviderId || !input.repo || !input.owner) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const gitlabProvider = await getGitlabProvider(input.gitlabProviderId);
|
const gitlabProvider = await getGitlabProvider(input.gitlabProviderId);
|
||||||
|
|
||||||
const projectResponse = await fetch(
|
const projectResponse = await fetch(
|
||||||
`https://gitlab.com/api/v4/projects?search=${input.repo}&owned=true&page=1&per_page=100`,
|
`https://gitlab.com/api/v4/projects?search=${input.repo}&owned=true&page=1&per_page=100`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${gitlabProvider.refreshToken}`,
|
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -324,3 +329,61 @@ export const gitProvider = createTRPCRouter({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
async function refreshGitlabToken(gitlabProviderId: string) {
|
||||||
|
const gitlabProvider = await getGitlabProvider(gitlabProviderId);
|
||||||
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
const safetyMargin = 60;
|
||||||
|
if (
|
||||||
|
gitlabProvider.expiresAt &&
|
||||||
|
currentTime + safetyMargin < gitlabProvider.expiresAt
|
||||||
|
) {
|
||||||
|
console.log("Token still valid, no need to refresh");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch("https://gitlab.com/oauth/token", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
grant_type: "refresh_token",
|
||||||
|
refresh_token: gitlabProvider.refreshToken as string,
|
||||||
|
client_id: gitlabProvider.applicationId as string,
|
||||||
|
client_secret: gitlabProvider.secret as string,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to refresh token: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
const expiresAt = Math.floor(Date.now() / 1000) + data.expires_in;
|
||||||
|
|
||||||
|
await updateGitlabProvider(gitlabProviderId, {
|
||||||
|
accessToken: data.access_token,
|
||||||
|
refreshToken: data.refresh_token,
|
||||||
|
expiresAt,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// 1725175543
|
||||||
|
// {
|
||||||
|
// access_token: '11d422887d8fac712191ee9b09dfdb043a705938cd67a4a39f36b4bc65b3106d',
|
||||||
|
// token_type: 'Bearer',
|
||||||
|
// expires_in: 7200,
|
||||||
|
// refresh_token: '3806d8022d32886c19d91eb9d1cea9328b864387f39c5d0469d08c48e18b674e',
|
||||||
|
// scope: 'api read_user read_repository',
|
||||||
|
// created_at: 1725167656
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// access_token: 'd256b52b10bf72ebf2784f8c0528e48a04a7d249c28695b6cc105b47b09c7336',
|
||||||
|
// token_type: 'Bearer',
|
||||||
|
// expires_in: 7200,
|
||||||
|
// refresh_token: '265eb87d0bbef410e0c30a2c239c4fa3698943219a439fb43cf2f8227d1fcaf2',
|
||||||
|
// scope: 'api read_user read_repository',
|
||||||
|
// created_at: 1725167803
|
||||||
|
// }
|
||||||
|
@ -83,6 +83,7 @@ export const gitlabProvider = pgTable("gitlab_provider", {
|
|||||||
accessToken: text("access_token"),
|
accessToken: text("access_token"),
|
||||||
refreshToken: text("refresh_token"),
|
refreshToken: text("refresh_token"),
|
||||||
groupName: text("group_name"),
|
groupName: text("group_name"),
|
||||||
|
expiresAt: integer("expires_at"),
|
||||||
gitProviderId: text("gitProviderId")
|
gitProviderId: text("gitProviderId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => gitProvider.gitProviderId, { onDelete: "cascade" }),
|
.references(() => gitProvider.gitProviderId, { onDelete: "cascade" }),
|
||||||
|
Loading…
Reference in New Issue
Block a user