diff --git a/client/src/pages/Admin/Settings/components/subcomponents/forms/GitForm.tsx b/client/src/pages/Admin/Settings/components/subcomponents/forms/GitForm.tsx index aae9461b..217fe991 100644 --- a/client/src/pages/Admin/Settings/components/subcomponents/forms/GitForm.tsx +++ b/client/src/pages/Admin/Settings/components/subcomponents/forms/GitForm.tsx @@ -4,6 +4,7 @@ import { ProFormSelect, ProFormText, } from '@ant-design/pro-components'; +import { message } from 'antd'; import React from 'react'; import { API, SsmGit } from 'ssm-shared-lib'; @@ -68,7 +69,23 @@ const GitForm: React.FC = ({ selectedRecord, repositories }) => ( name={'remoteUrl'} label={'Remote Url'} initialValue={selectedRecord?.remoteUrl} - rules={[{ required: true }]} + rules={[ + { required: true }, + { type: 'url' }, + { pattern: /https:\/\//, message: 'Please include https://' }, + ]} + fieldProps={{ + onBlur: (e) => { + const value = e.target.value; + const regex = /https?:\/\/[^@\n]+:[^@\n]+@/; // Matches user:password@ in URLs + if (regex.test(value)) { + void message.warning({ + content: + 'Remote URL contains a username or access token. Consider removing it for security.', + }); + } + }, + }} /> + trim( + rawUrl.replaceAll('\n', '').replace( + /https?:\/\/([a-zA-Z0-9.-]+(:\d+)?)(\/.*)/, // Matches domain, optional port, and trailing path + `https://${username}:${accessToken}@$1$3`, // Replaces with credentials and preserves the rest of the path + ), + ); + const getUrlWithOutCredential = (urlWithCredential: string): string => trim(urlWithCredential.replace(/.+@/, 'https://')); @@ -58,6 +71,7 @@ const getUrlWithOutCredential = (urlWithCredential: string): string => * @param accessToken * @param remoteName * @param serviceType + * @param domain */ export async function credentialOn( directory: string, @@ -85,7 +99,15 @@ export async function credentialOn( gitUrlWithCredential = getAzureReposUrlWithCredential(remoteUrl, userName, accessToken); break; } + case SsmGit.Services.Gitea: { + gitUrlWithCredential = getGiteaUrlWithCredential(remoteUrl, userName, accessToken); + break; + } + default: { + throw new Error(`Unknown service type ${serviceType}`); + } } + logger.error(gitUrlWithCredential); await GitProcess.exec(['remote', 'add', remoteName, gitUrlWithCredential], directory); await GitProcess.exec(['remote', 'set-url', remoteName, gitUrlWithCredential], directory); } @@ -103,23 +125,18 @@ export async function credentialOff( serviceType = SsmGit.Services.Github, ): Promise { const gitRepoUrl = remoteUrl ?? (await getRemoteUrl(directory, remoteName)); - let gitUrlWithOutCredential; + let gitUrlWithOutCredential: string; switch (serviceType) { - case SsmGit.Services.Github: { + case SsmGit.Services.Github: + case SsmGit.Services.GitLab: + case SsmGit.Services.Bitbucket: + case SsmGit.Services.AzureRepos: + case SsmGit.Services.Gitea: { gitUrlWithOutCredential = getUrlWithOutCredential(gitRepoUrl); break; } - case SsmGit.Services.GitLab: { - gitUrlWithOutCredential = getUrlWithOutCredential(gitRepoUrl); - break; - } - case SsmGit.Services.Bitbucket: { - gitUrlWithOutCredential = getUrlWithOutCredential(gitRepoUrl); - break; - } - case SsmGit.Services.AzureRepos: { - gitUrlWithOutCredential = getUrlWithOutCredential(gitRepoUrl); - break; + default: { + throw new Error(`Unknown service type ${serviceType}`); } } await GitProcess.exec(['remote', 'set-url', remoteName, gitUrlWithOutCredential], directory); diff --git a/server/src/modules/repository/git-playbooks-repository/GitPlaybooksRepositoryComponent.ts b/server/src/modules/repository/git-playbooks-repository/GitPlaybooksRepositoryComponent.ts index 0de6de47..35861c38 100644 --- a/server/src/modules/repository/git-playbooks-repository/GitPlaybooksRepositoryComponent.ts +++ b/server/src/modules/repository/git-playbooks-repository/GitPlaybooksRepositoryComponent.ts @@ -60,6 +60,7 @@ class GitPlaybooksRepositoryComponent async clone(syncAfter = false) { this.childLogger.info('Clone starting...'); try { + await GitPlaybooksRepositoryUseCases.resetRepositoryError(this.uuid); try { void Shell.FileSystemManager.createDirectory(this.directory, DIRECTORY_ROOT); } catch (error: any) { @@ -101,6 +102,7 @@ class GitPlaybooksRepositoryComponent async commitAndSync() { try { + await GitPlaybooksRepositoryUseCases.resetRepositoryError(this.uuid); await commitAndSync({ ...this.options, logger: { @@ -134,6 +136,7 @@ class GitPlaybooksRepositoryComponent async forcePull() { try { + await GitPlaybooksRepositoryUseCases.resetRepositoryError(this.uuid); await forcePull({ ...this.options, logger: { diff --git a/shared-lib/src/enums/git.ts b/shared-lib/src/enums/git.ts index 3bcdbbcd..2ab6d727 100644 --- a/shared-lib/src/enums/git.ts +++ b/shared-lib/src/enums/git.ts @@ -2,5 +2,6 @@ export enum Services { Github = 'github', GitLab = 'gitlab', Bitbucket = 'bitbucket', - AzureRepos = 'azure-repos' + AzureRepos = 'azure-repos', + Gitea = 'gitea' }