Merge branch 'main' into next
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	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');
 | 
			
		||||
@@ -29,13 +29,9 @@
 | 
			
		||||
	};
 | 
			
		||||
	let showSave = false;
 | 
			
		||||
	async function loadRepositoriesByPage(page = 0) {
 | 
			
		||||
		try {
 | 
			
		||||
			return await get(`${apiUrl}/installation/repositories?per_page=100&page=${page}`, {
 | 
			
		||||
				Authorization: `token ${$session.ghToken}`
 | 
			
		||||
			});
 | 
			
		||||
		} catch ({ error }) {
 | 
			
		||||
			return errorNotification(error);
 | 
			
		||||
		}
 | 
			
		||||
		return await get(`${apiUrl}/installation/repositories?per_page=100&page=${page}`, {
 | 
			
		||||
			Authorization: `token ${$gitTokens.githubToken}`
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
	async function loadRepositories() {
 | 
			
		||||
		let page = 1;
 | 
			
		||||
@@ -58,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 }) {
 | 
			
		||||
@@ -85,7 +81,47 @@
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	onMount(async () => {
 | 
			
		||||
		await loadRepositories();
 | 
			
		||||
		try {
 | 
			
		||||
			if (!$gitTokens.githubToken) {
 | 
			
		||||
				const { token } = await get(`/applications/${id}/configuration/githubToken.json`);
 | 
			
		||||
				$gitTokens.githubToken = token;
 | 
			
		||||
			}
 | 
			
		||||
			await loadRepositories();
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			if (
 | 
			
		||||
				error.error === 'invalid_token' ||
 | 
			
		||||
				error.error_description ===
 | 
			
		||||
					'Token is expired. You can either do re-authorization or token refresh.' ||
 | 
			
		||||
				error.message === '401 Unauthorized'
 | 
			
		||||
			) {
 | 
			
		||||
				if (application.gitSource.gitlabAppId) {
 | 
			
		||||
					let htmlUrl = application.gitSource.htmlUrl;
 | 
			
		||||
					const left = screen.width / 2 - 1020 / 2;
 | 
			
		||||
					const top = screen.height / 2 - 618 / 2;
 | 
			
		||||
					const newWindow = open(
 | 
			
		||||
						`${htmlUrl}/oauth/authorize?client_id=${application.gitSource.gitlabApp.appId}&redirect_uri=${window.location.origin}/webhooks/gitlab&response_type=code&scope=api+email+read_repository&state=${$page.params.id}`,
 | 
			
		||||
						'GitLab',
 | 
			
		||||
						'resizable=1, scrollbars=1, fullscreen=0, height=618, width=1020,top=' +
 | 
			
		||||
							top +
 | 
			
		||||
							', left=' +
 | 
			
		||||
							left +
 | 
			
		||||
							', toolbar=0, menubar=0, status=0'
 | 
			
		||||
					);
 | 
			
		||||
					const timer = setInterval(() => {
 | 
			
		||||
						if (newWindow?.closed) {
 | 
			
		||||
							clearInterval(timer);
 | 
			
		||||
							window.location.reload();
 | 
			
		||||
						}
 | 
			
		||||
					}, 100);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (error.message === 'Bad credentials') {
 | 
			
		||||
				const { token } = await get(`/applications/${id}/configuration/githubToken.json`);
 | 
			
		||||
				$gitTokens.githubToken = token;
 | 
			
		||||
				return await loadRepositories();
 | 
			
		||||
			}
 | 
			
		||||
			return errorNotification(error);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	async function handleSubmit() {
 | 
			
		||||
		try {
 | 
			
		||||
 
 | 
			
		||||
@@ -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 });
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
	import { page, session } from '$app/stores';
 | 
			
		||||
	import { get } from '$lib/api';
 | 
			
		||||
	import { errorNotification } from '$lib/form';
 | 
			
		||||
	import { browser } from '$app/env';
 | 
			
		||||
	import { gitTokens } from '$lib/store';
 | 
			
		||||
 | 
			
		||||
	let scanning = true;
 | 
			
		||||
	let foundConfig = null;
 | 
			
		||||
@@ -62,7 +62,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'
 | 
			
		||||
@@ -89,7 +89,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) || {};
 | 
			
		||||
@@ -105,7 +105,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(
 | 
			
		||||
@@ -130,7 +130,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) || {};
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	export let application;
 | 
			
		||||
	export let appId;
 | 
			
		||||
 | 
			
		||||
	import GithubRepositories from './_GithubRepositories.svelte';
 | 
			
		||||
	import GitlabRepositories from './_GitlabRepositories.svelte';
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +1,37 @@
 | 
			
		||||
import { getTeam, getUserDetails } from '$lib/common';
 | 
			
		||||
import { getGithubToken } from '$lib/components/common';
 | 
			
		||||
import { getUserDetails } from '$lib/common';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import { ErrorHandler } from '$lib/database';
 | 
			
		||||
import { checkContainer } from '$lib/haproxy';
 | 
			
		||||
import type { RequestHandler } from '@sveltejs/kit';
 | 
			
		||||
import jsonwebtoken from 'jsonwebtoken';
 | 
			
		||||
import { get as getRequest } from '$lib/api';
 | 
			
		||||
 | 
			
		||||
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 });
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user