fix: Move tokens from session to cookie/store

This commit is contained in:
Andras Bacsai 2022-02-21 12:35:20 +01:00
parent 954a265965
commit fcfa8717a5
10 changed files with 108 additions and 88 deletions

View File

@ -17,8 +17,6 @@ export const handle = handleSession(
let response;
try {
if (event.locals.cookies) {
let gitlabToken = event.locals.cookies.gitlabToken || null;
let ghToken = event.locals.cookies.ghToken || null;
if (event.locals.cookies['kit.session']) {
const { permission, teamId, userId } = await getUserDetails(event, false);
const newSession = {
@ -26,9 +24,7 @@ export const handle = handleSession(
teamId,
permission,
isAdmin: permission === 'admin' || permission === 'owner',
expires: event.locals.session.data.expires,
gitlabToken,
ghToken
expires: event.locals.session.data.expires
};
if (JSON.stringify(event.locals.session.data) !== JSON.stringify(newSession)) {

View File

@ -9,22 +9,6 @@ export const dateOptions: DateTimeFormatOptions = {
hour12: false
};
export async function getGithubToken({ apiUrl, application, githubToken }): Promise<void> {
const response = await fetch(
`${apiUrl}/app/installations/${application.gitSource.githubApp.installationId}/access_tokens`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${githubToken}`
}
}
);
if (!response.ok) {
throw new Error('Git Source not configured.');
}
const data = await response.json();
return data.token;
}
export const staticDeployments = ['react', 'vuejs', 'static', 'svelte', 'gatsby', 'php'];
export const notNodeDeployments = ['php', 'docker', 'rust'];

6
src/lib/store.ts Normal file
View File

@ -0,0 +1,6 @@
import { writable } from 'svelte/store';
export const gitTokens = writable({
githubToken: null,
gitlabToken: null
});

View File

@ -17,13 +17,20 @@
const endpoint = `/applications/${params.id}.json`;
const res = await fetch(endpoint);
if (res.ok) {
const { application, isRunning, appId } = await res.json();
let { application, isRunning, appId, githubToken, gitlabToken } = await res.json();
if (!application || Object.entries(application).length === 0) {
return {
status: 302,
redirect: '/applications'
};
}
if (application.gitSource?.githubAppId && !githubToken) {
const response = await fetch(`/applications/${params.id}/configuration/githubToken.json`);
if (response.ok) {
const { token } = await response.json();
githubToken = token;
}
}
const configurationPhase = checkConfiguration(application);
if (
configurationPhase &&
@ -38,7 +45,9 @@
return {
props: {
application,
isRunning
isRunning,
githubToken,
gitlabToken
},
stuff: {
isRunning,
@ -58,12 +67,18 @@
<script lang="ts">
export let application;
export let isRunning;
export let githubToken;
export let gitlabToken;
import { page, session } from '$app/stores';
import { errorNotification } from '$lib/form';
import DeleteIcon from '$lib/components/DeleteIcon.svelte';
import Loading from '$lib/components/Loading.svelte';
import { del, post } from '$lib/api';
import { goto } from '$app/navigation';
import { gitTokens } from '$lib/store';
if (githubToken) $gitTokens.githubToken = githubToken;
if (gitlabToken) $gitTokens.gitlabToken = gitlabToken;
let loading = false;
const { id } = $page.params;

View File

@ -1,14 +1,12 @@
<script lang="ts">
import { browser } from '$app/env';
import { goto } from '$app/navigation';
export let application;
import { page, session } from '$app/stores';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { get, post } from '$lib/api';
import { errorNotification } from '$lib/form';
import { onMount } from 'svelte';
import { gitTokens } from '$lib/store';
const { id } = $page.params;
const from = $page.url.searchParams.get('from');
@ -32,7 +30,7 @@
let showSave = false;
async function loadRepositoriesByPage(page = 0) {
return await get(`${apiUrl}/installation/repositories?per_page=100&page=${page}`, {
Authorization: `token ${$session.ghToken}`
Authorization: `token ${$gitTokens.githubToken}`
});
}
async function loadRepositories() {
@ -56,7 +54,7 @@
selected.projectId = repositories.find((repo) => repo.full_name === selected.repository).id;
try {
branches = await get(`${apiUrl}/repos/${selected.repository}/branches`, {
Authorization: `token ${$session.ghToken}`
Authorization: `token ${$gitTokens.githubToken}`
});
return;
} catch ({ error }) {
@ -84,6 +82,10 @@
onMount(async () => {
try {
if (!$gitTokens.githubToken) {
const { token } = await get(`/applications/${id}/configuration/githubToken.json`);
$gitTokens.githubToken = token;
}
await loadRepositories();
} catch (error) {
if (
@ -114,7 +116,9 @@
}
}
if (error.message === 'Bad credentials') {
browser && window.location.reload();
const { token } = await get(`/applications/${id}/configuration/githubToken.json`);
$gitTokens.githubToken = token;
return await loadRepositories();
}
return errorNotification(error);
}

View File

@ -8,6 +8,8 @@
import cuid from 'cuid';
import { goto } from '$app/navigation';
import { del, get, post, put } from '$lib/api';
import { gitTokens } from '$lib/store';
const { id } = $page.params;
const from = $page.url.searchParams.get('from');
@ -35,13 +37,13 @@
branch: undefined
};
onMount(async () => {
if (!$session.gitlabToken) {
if (!$gitTokens.gitlabToken) {
getGitlabToken();
} else {
loading.base = true;
try {
const user = await get(`${apiUrl}/v4/user`, {
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
});
username = user.username;
} catch (error) {
@ -49,7 +51,7 @@
}
try {
groups = await get(`${apiUrl}/v4/groups?per_page=5000`, {
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
});
} catch (error) {
errorNotification(error);
@ -87,7 +89,7 @@
projects = await get(
`${apiUrl}/v4/users/${selected.group.name}/projects?min_access_level=40&page=1&per_page=25&archived=false`,
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
} catch (error) {
@ -101,7 +103,7 @@
projects = await get(
`${apiUrl}/v4/groups/${selected.group.id}/projects?page=1&per_page=25&archived=false`,
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
} catch (error) {
@ -119,7 +121,7 @@
branches = await get(
`${apiUrl}/v4/projects/${selected.project.id}/repository/branches?per_page=100&page=1`,
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
} catch (error) {
@ -169,7 +171,7 @@
merge_requests_events: true
},
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
} catch (error) {
@ -193,7 +195,7 @@
publicSshKey = publicKey;
}
const deployKeys = await get(deployKeyUrl, {
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
});
const deployKeyFound = deployKeys.filter((dk) => dk.title === `${appId}-coolify-deploy-key`);
if (deployKeyFound.length > 0) {
@ -202,7 +204,7 @@
`${deployKeyUrl}/${deployKey.id}`,
{},
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
}
@ -215,7 +217,7 @@
can_push: false
},
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
await post(updateDeployKeyIdUrl, { deployKeyId: id });

View File

@ -34,6 +34,7 @@
import { page, session } from '$app/stores';
import { get } from '$lib/api';
import { errorNotification } from '$lib/form';
import { gitTokens } from '$lib/store';
let scanning = true;
let foundConfig = null;
@ -59,7 +60,7 @@
try {
if (type === 'gitlab') {
const files = await get(`${apiUrl}/v4/projects/${projectId}/repository/tree`, {
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
});
const packageJson = files.find(
(file) => file.name === 'package.json' && file.type === 'blob'
@ -78,7 +79,7 @@
const data = await get(
`${apiUrl}/v4/projects/${projectId}/repository/files/${path}/raw?ref=${branch}`,
{
Authorization: `Bearer ${$session.gitlabToken}`
Authorization: `Bearer ${$gitTokens.gitlabToken}`
}
);
const json = JSON.parse(data) || {};
@ -94,7 +95,7 @@
}
} else if (type === 'github') {
const files = await get(`${apiUrl}/repos/${repository}/contents?ref=${branch}`, {
Authorization: `Bearer ${$session.ghToken}`,
Authorization: `Bearer ${$gitTokens.githubToken}`,
Accept: 'application/vnd.github.v2.json'
});
const packageJson = files.find(
@ -111,7 +112,7 @@
foundConfig.buildPack = 'docker';
} else if (packageJson) {
const data = await get(`${packageJson.git_url}`, {
Authorization: `Bearer ${$session.ghToken}`,
Authorization: `Bearer ${$gitTokens.githubToken}`,
Accept: 'application/vnd.github.v2.raw'
});
const json = JSON.parse(data) || {};

View File

@ -0,0 +1,45 @@
import { getUserDetails } from '$lib/common';
import * as db from '$lib/database';
import { ErrorHandler } from '$lib/database';
import type { RequestHandler } from '@sveltejs/kit';
import jsonwebtoken from 'jsonwebtoken';
export const get: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event);
if (status === 401) return { status, body };
const { id } = event.params;
try {
const application = await db.getApplication({ id, teamId });
const payload = {
iat: Math.round(new Date().getTime() / 1000),
exp: Math.round(new Date().getTime() / 1000 + 60),
iss: application.gitSource.githubApp.appId
};
const githubToken = jsonwebtoken.sign(payload, application.gitSource.githubApp.privateKey, {
algorithm: 'RS256'
});
const response = await fetch(
`${application.gitSource.apiUrl}/app/installations/${application.gitSource.githubApp.installationId}/access_tokens`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${githubToken}`
}
}
);
if (!response.ok) {
throw new Error(`${response.status} ${response.statusText}`);
}
const data = await response.json();
return {
status: 201,
body: { token: data.token },
headers: {
'Set-Cookie': `githubToken=${data.token}; Path=/; HttpOnly; Max-Age=15778800;`
}
};
} catch (error) {
return ErrorHandler(error);
}
};

View File

@ -20,6 +20,7 @@
<script lang="ts">
export let application;
export let appId;
import GithubRepositories from './_GithubRepositories.svelte';
import GitlabRepositories from './_GitlabRepositories.svelte';
</script>

View File

@ -1,5 +1,4 @@
import { getUserDetails } from '$lib/common';
import { getGithubToken } from '$lib/components/common';
import * as db from '$lib/database';
import { ErrorHandler } from '$lib/database';
import { checkContainer } from '$lib/haproxy';
@ -11,61 +10,28 @@ export const get: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event);
if (status === 401) return { status, body };
const appId = process.env['COOLIFY_APP_ID'];
let githubToken = null;
let ghToken = null;
let isRunning = false;
const { id } = event.params;
const appId = process.env['COOLIFY_APP_ID'];
let isRunning = false;
let githubToken = event.locals.cookies?.githubToken || null;
let gitlabToken = event.locals.cookies?.gitlabToken || null;
try {
const application = await db.getApplication({ id, teamId });
const { gitSource } = application;
if (gitSource?.type === 'github' && gitSource?.githubApp) {
if (!event.locals.session.data.ghToken) {
const payload = {
iat: Math.round(new Date().getTime() / 1000),
exp: Math.round(new Date().getTime() / 1000 + 600),
iss: gitSource.githubApp.appId
};
githubToken = jsonwebtoken.sign(payload, gitSource.githubApp.privateKey, {
algorithm: 'RS256'
});
ghToken = await getGithubToken({ apiUrl: gitSource.apiUrl, application, githubToken });
} else {
try {
await getRequest(`${gitSource.apiUrl}/installation/repositories`, {
Authorization: `token ${event.locals.session.data.ghToken}`
});
} catch (error) {
const payload = {
iat: Math.round(new Date().getTime() / 1000),
exp: Math.round(new Date().getTime() / 1000 + 600),
iss: gitSource.githubApp.appId
};
githubToken = jsonwebtoken.sign(payload, gitSource.githubApp.privateKey, {
algorithm: 'RS256'
});
ghToken = await getGithubToken({ apiUrl: gitSource.apiUrl, application, githubToken });
}
}
}
if (application.destinationDockerId) {
isRunning = await checkContainer(application.destinationDocker.engine, id);
}
const payload = {
return {
status: 200,
body: {
isRunning,
application,
appId
appId,
githubToken,
gitlabToken
},
headers: {}
};
if (ghToken) {
payload.headers = {
'set-cookie': [`ghToken=${ghToken}; HttpOnly; Path=/; Max-Age=15778800;`]
};
}
return payload;
} catch (error) {
console.log(error);
return ErrorHandler(error);