mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
Merge pull request #231 from fporrmann/ext-ce-gitlab
GitLab Synchronization - Bugfix and cleanup
This commit is contained in:
@@ -190,7 +190,7 @@ async function fetchAllPages(url, options, operation) {
|
||||
}
|
||||
|
||||
function getTokenRefreshTimestamp(token, safetyMarginInSec = 300) {
|
||||
return token.created_at + token.expires_in - safetyMarginInSec;
|
||||
return token.created_at + token.expires_in - safetyMarginInSec;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,8 +200,8 @@ async function compareCommitsFull(token, repoFullName, from, to) {
|
||||
url.searchParams.set('to', to)
|
||||
|
||||
return await fetchGitLabJson(url.toString(), {
|
||||
headers: buildHeaders(token),
|
||||
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
||||
headers: buildHeaders(token),
|
||||
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
||||
}, 'compareCommitsFull')
|
||||
}
|
||||
|
||||
@@ -224,8 +224,8 @@ function exchangeCodeForToken(code) {
|
||||
headers: buildHeaders(),
|
||||
json: {
|
||||
client_id: Settings.gitlabSync.clientID,
|
||||
client_secret: Settings.gitlabSync.clientSecret,
|
||||
code: code,
|
||||
client_secret: Settings.gitlabSync.clientSecret,
|
||||
code: code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: Settings.gitlabSync.callbackURL,
|
||||
},
|
||||
@@ -468,7 +468,7 @@ async function getBlobContent(token, repoFullName, sha) {
|
||||
return await fetchGitLabJson(url, {
|
||||
headers: buildHeaders(token),
|
||||
signal: AbortSignal.timeout(REQUEST_LONG_TIMEOUT_MS)
|
||||
}, 'getBlobContent').then(r => Buffer.from(r.content, 'base64'))
|
||||
}, 'getBlobContent').then(r => r.content || '')
|
||||
}
|
||||
|
||||
async function listNewCommitsWithStatus(token, fullName, branchName, fromCommit) {
|
||||
|
||||
@@ -118,14 +118,14 @@ async function oauth2Callback(req, res) {
|
||||
let refresh_token
|
||||
let refresh_timestamp
|
||||
try {
|
||||
[token, refresh_token, refresh_timestamp] = await api.exchangeCodeForToken(code)
|
||||
[token, refresh_token, refresh_timestamp] = await api.exchangeCodeForToken(code)
|
||||
if (!token || !refresh_token) {
|
||||
HttpErrorHandler.badRequest(req, res, 'Failed to obtain access token from Git server')
|
||||
return
|
||||
}
|
||||
} catch (err) {
|
||||
const info = OError.getFullInfo(err)
|
||||
const err_body = err.body
|
||||
const err_body = err.body
|
||||
logger.error(OError.getFullStack(err))
|
||||
logger.error({ info, err_body, userId }, 'Failed to obtain access token from Git server')
|
||||
HttpErrorHandler.badRequest(req, res, err.message || 'Bad request')
|
||||
|
||||
@@ -18,17 +18,16 @@ import { InvalidTokenError, NotFoundError } from './GitSyncErrors.mjs'
|
||||
|
||||
async function getGitConnState(userId) {
|
||||
try {
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) return false;
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) return false;
|
||||
|
||||
await api.getUser(token)
|
||||
await api.getUser(token)
|
||||
return true
|
||||
} catch (err) {
|
||||
if (err instanceof InvalidTokenError) {
|
||||
logger.debug( { err, userId }, 'token invalid, treating as not connected')
|
||||
return false
|
||||
}
|
||||
}
|
||||
throw OError.tag(err, 'failed to validate token', { userId })
|
||||
}
|
||||
}
|
||||
@@ -52,9 +51,9 @@ async function getProjectState(userId, projectId) {
|
||||
}
|
||||
let canPush
|
||||
try {
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
|
||||
canPush = await api.getPushPermission(token, pss.repoFullName)
|
||||
} catch (err) {
|
||||
if ((err instanceof NotFoundError) ||
|
||||
@@ -97,16 +96,14 @@ async function unlinkRepo(userId, projectId) {
|
||||
|
||||
|
||||
async function listUserRepos(userId) {
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
return await api.listUserRepos(token)
|
||||
}
|
||||
|
||||
async function getUserAndOrgs(userId) {
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
return await api.getUserAndOrgs(token)
|
||||
}
|
||||
|
||||
@@ -117,9 +114,8 @@ async function getMergeOverview(userId, projectId) {
|
||||
|
||||
if (mergeStatus === 'conflict') return null
|
||||
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const currentVersion = await HistoryManager.latestVersion(projectId.toString())
|
||||
const isProjectUpdated = currentVersion !== lastSyncVersion
|
||||
try {
|
||||
@@ -148,9 +144,8 @@ async function getMergeOverview(userId, projectId) {
|
||||
}
|
||||
|
||||
async function importRepo(userId, projectName, repoFullName, defaultBranchName) {
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const defaultBranchHead = await api.getBranchHead(token, repoFullName, defaultBranchName)
|
||||
const fsPath = Path.join(Settings.path.dumpFolder, `gitlab_import_${crypto.randomUUID()}`)
|
||||
|
||||
@@ -203,9 +198,8 @@ async function exportProject(userId, projectId, repoOptions) {
|
||||
throw new OError('Project is already linked to Git server', { projectId })
|
||||
}
|
||||
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
|
||||
const { path_with_namespace: repoFullName, default_branch: defaultBranchName } =
|
||||
await api.createRepo(token, repoOptions)
|
||||
|
||||
@@ -40,9 +40,8 @@ async function doGitMergeWithoutLock(userId, projectId, message, claimConflictIs
|
||||
claimConflictIsResolved && mergeStatus !== 'conflict'
|
||||
) return { mergeStatus, repoFullName, unmergedBranchName }
|
||||
|
||||
const tokens = await TokenManager.getUserToken(userId)
|
||||
if (!tokens) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
const { token } = tokens
|
||||
const token = await TokenManager.getUserToken(userId)
|
||||
if (!token) throw new InvalidTokenError('no user token', { userId, status: 400 });
|
||||
|
||||
await DocumentUpdaterHandler.promises.flushProjectToMongo(projectId)
|
||||
|
||||
@@ -278,8 +277,7 @@ async function resolveConflictSyncState(
|
||||
token,
|
||||
repoFullName,
|
||||
defaultBranchName,
|
||||
newOlBranchHead,
|
||||
tempBranchName,
|
||||
tempBranchName
|
||||
)
|
||||
|
||||
if (conflict) {
|
||||
|
||||
@@ -24,61 +24,61 @@ async function decryptAccessToken(tokenEncrypted) {
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshToken(userId, tokens) {
|
||||
logger.info({ userId }, "refreshing GitLab token")
|
||||
async function refreshToken(userId, decData) {
|
||||
logger.info({ userId }, "refreshing GitLab token")
|
||||
|
||||
if (!tokens.refresh_token) {
|
||||
logger.error("refresh_token invalid")
|
||||
return false
|
||||
}
|
||||
if (!decData.refresh_token) {
|
||||
logger.error("refresh_token invalid")
|
||||
return false
|
||||
}
|
||||
|
||||
let token
|
||||
let refresh_token
|
||||
let refresh_timestamp
|
||||
let token
|
||||
let refresh_token
|
||||
let refresh_timestamp
|
||||
|
||||
try {
|
||||
[token, refresh_token, refresh_timestamp] = await api.refreshToken(tokens.refresh_token)
|
||||
if (!token || !refresh_token) {
|
||||
HttpErrorHandler.badRequest(req, res, 'Failed to refresh access token')
|
||||
return false
|
||||
}
|
||||
} catch (err) {
|
||||
const info = OError.getFullInfo(err)
|
||||
logger.error(OError.getFullStack(err))
|
||||
logger.error({ info, userId }, 'Failed to refresh access token')
|
||||
HttpErrorHandler.badRequest(req, res, err.message || 'Bad request')
|
||||
return false
|
||||
}
|
||||
try {
|
||||
[token, refresh_token, refresh_timestamp] = await api.refreshToken(decData.refresh_token)
|
||||
if (!token || !refresh_token) {
|
||||
HttpErrorHandler.badRequest(req, res, 'Failed to refresh access token')
|
||||
return false
|
||||
}
|
||||
} catch (err) {
|
||||
const info = OError.getFullInfo(err)
|
||||
logger.error(OError.getFullStack(err))
|
||||
logger.error({ info, userId }, 'Failed to refresh access token')
|
||||
HttpErrorHandler.badRequest(req, res, err.message || 'Bad request')
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
await saveUserToken(userId, { token, refresh_token, refresh_timestamp })
|
||||
} catch (err) {
|
||||
const info = OError.getFullInfo(err)
|
||||
const errStatus = info?.status || 500
|
||||
logger.error(OError.getFullStack(err))
|
||||
logger.error({ info, userId }, 'Error saving user token')
|
||||
HttpErrorHandler.handleErrorByStatusCode(req, res, err, errStatus)
|
||||
return false
|
||||
}
|
||||
try {
|
||||
await saveUserToken(userId, { token, refresh_token, refresh_timestamp })
|
||||
} catch (err) {
|
||||
const info = OError.getFullInfo(err)
|
||||
const errStatus = info?.status || 500
|
||||
logger.error(OError.getFullStack(err))
|
||||
logger.error({ info, userId }, 'Error saving user token')
|
||||
HttpErrorHandler.handleErrorByStatusCode(req, res, err, errStatus)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return true
|
||||
}
|
||||
|
||||
// ------------------------- exports -------------------------- //
|
||||
async function getUserToken(userId) {
|
||||
const credentials = await GitLabSyncUserCredentials.findOne(normalizeQuery({ userId }))
|
||||
if (!credentials) throw new InvalidTokenError('no user token', { userId, status: 400 })
|
||||
let tokens = await decryptAccessToken(credentials.gitlab)
|
||||
let decData = await decryptAccessToken(credentials.gitlab)
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
if (!tokens.refresh_timestamp || tokens.refresh_timestamp < now) {
|
||||
const refreshed = await refreshToken(userId, tokens)
|
||||
if (refreshed) {
|
||||
return await getUserToken(userId)
|
||||
}
|
||||
if (!decData.refresh_timestamp || decData.refresh_timestamp < now) {
|
||||
const refreshed = await refreshToken(userId, decData)
|
||||
if (refreshed) {
|
||||
return await getUserToken(userId)
|
||||
}
|
||||
}
|
||||
|
||||
return tokens
|
||||
return decData.token
|
||||
}
|
||||
|
||||
async function saveUserToken(userId, accessToken) {
|
||||
|
||||
Reference in New Issue
Block a user