mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36:06 +08:00
重构私有仓库ssh配置逻辑
This commit is contained in:
parent
083c8869aa
commit
b27ee23cc3
4
.github/workflows/build_docker_image.yml
vendored
4
.github/workflows/build_docker_image.yml
vendored
|
@ -44,8 +44,6 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
with:
|
|
||||||
version: 7
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
@ -98,8 +96,6 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
with:
|
|
||||||
version: 7
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -27,6 +27,7 @@ const bakPath = path.join(dataPath, 'bak/');
|
||||||
const logPath = path.join(dataPath, 'log/');
|
const logPath = path.join(dataPath, 'log/');
|
||||||
const dbPath = path.join(dataPath, 'db/');
|
const dbPath = path.join(dataPath, 'db/');
|
||||||
const uploadPath = path.join(dataPath, 'upload/');
|
const uploadPath = path.join(dataPath, 'upload/');
|
||||||
|
const sshdPath = path.join(dataPath, 'ssh.d/');
|
||||||
|
|
||||||
const envFile = path.join(configPath, 'env.sh');
|
const envFile = path.join(configPath, 'env.sh');
|
||||||
const confFile = path.join(configPath, 'config.sh');
|
const confFile = path.join(configPath, 'config.sh');
|
||||||
|
@ -95,4 +96,5 @@ export default {
|
||||||
versionFile,
|
versionFile,
|
||||||
lastVersionFile,
|
lastVersionFile,
|
||||||
sqliteFile,
|
sqliteFile,
|
||||||
|
sshdPath,
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@ const sampleConfigFile = path.join(samplePath, 'config.sample.sh');
|
||||||
const sampleAuthFile = path.join(samplePath, 'auth.sample.json');
|
const sampleAuthFile = path.join(samplePath, 'auth.sample.json');
|
||||||
const homedir = os.homedir();
|
const homedir = os.homedir();
|
||||||
const sshPath = path.resolve(homedir, '.ssh');
|
const sshPath = path.resolve(homedir, '.ssh');
|
||||||
|
const sshdPath = path.join(dataPath, 'ssh.d');
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
const authFileExist = await fileExist(authConfigFile);
|
const authFileExist = await fileExist(authConfigFile);
|
||||||
|
@ -29,6 +30,7 @@ export default async () => {
|
||||||
const uploadDirExist = await fileExist(uploadPath);
|
const uploadDirExist = await fileExist(uploadPath);
|
||||||
const sshDirExist = await fileExist(sshPath);
|
const sshDirExist = await fileExist(sshPath);
|
||||||
const bakDirExist = await fileExist(bakPath);
|
const bakDirExist = await fileExist(bakPath);
|
||||||
|
const sshdDirExist = await fileExist(sshdPath);
|
||||||
|
|
||||||
if (!configDirExist) {
|
if (!configDirExist) {
|
||||||
fs.mkdirSync(configPath);
|
fs.mkdirSync(configPath);
|
||||||
|
@ -62,6 +64,10 @@ export default async () => {
|
||||||
fs.mkdirSync(bakPath);
|
fs.mkdirSync(bakPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sshdDirExist) {
|
||||||
|
fs.mkdirSync(sshdPath);
|
||||||
|
}
|
||||||
|
|
||||||
dotenv.config({ path: confFile });
|
dotenv.config({ path: confFile });
|
||||||
|
|
||||||
Logger.info('✌️ Init file down');
|
Logger.info('✌️ Init file down');
|
||||||
|
|
|
@ -5,14 +5,25 @@ import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Subscription } from '../data/subscription';
|
import { Subscription } from '../data/subscription';
|
||||||
import { formatUrl } from '../config/subscription';
|
import { formatUrl } from '../config/subscription';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class SshKeyService {
|
export default class SshKeyService {
|
||||||
private homedir = os.homedir();
|
private homedir = os.homedir();
|
||||||
private sshPath = path.resolve(this.homedir, '.ssh');
|
private sshPath = config.sshdPath;
|
||||||
private sshConfigFilePath = path.resolve(this.sshPath, 'config');
|
private sshConfigFilePath = path.resolve(this.homedir, '.ssh', 'config');
|
||||||
|
private sshConfigHeader = `Include ${this.sshPath}*.config`;
|
||||||
|
|
||||||
constructor(@Inject('logger') private logger: winston.Logger) {}
|
constructor(@Inject('logger') private logger: winston.Logger) {
|
||||||
|
this.initSshConfigFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
private initSshConfigFile() {
|
||||||
|
const config = fs.readFileSync(this.sshConfigFilePath, { encoding: 'utf-8' })
|
||||||
|
if (!config.includes(this.sshConfigHeader)) {
|
||||||
|
fs.writeFileSync(this.sshConfigFilePath, `${this.sshConfigHeader}\n\n${config}`, { encoding: 'utf-8' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private generatePrivateKeyFile(alias: string, key: string): void {
|
private generatePrivateKeyFile(alias: string, key: string): void {
|
||||||
try {
|
try {
|
||||||
|
@ -25,18 +36,11 @@ export default class SshKeyService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getConfigRegx(alias: string) {
|
|
||||||
return new RegExp(
|
|
||||||
`Host ${alias}\n.*[^StrictHostKeyChecking]*.*[\n]*.*StrictHostKeyChecking no`,
|
|
||||||
'g',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private removePrivateKeyFile(alias: string): void {
|
private removePrivateKeyFile(alias: string): void {
|
||||||
try {
|
try {
|
||||||
const filePath = path.join(this.sshPath, alias);
|
const filePath = path.join(this.sshPath, alias);
|
||||||
if (existsSync(filePath)) {
|
if (existsSync(filePath)) {
|
||||||
fs.unlinkSync(`${this.sshPath}/${alias}`);
|
fs.unlinkSync(filePath);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error('删除私钥文件失败', error);
|
this.logger.error('删除私钥文件失败', error);
|
||||||
|
@ -47,34 +51,21 @@ export default class SshKeyService {
|
||||||
alias: string,
|
alias: string,
|
||||||
host: string,
|
host: string,
|
||||||
proxy?: string,
|
proxy?: string,
|
||||||
): string {
|
) {
|
||||||
if (host === 'github.com') {
|
if (host === 'github.com') {
|
||||||
host = `ssh.github.com\n Port 443\n HostkeyAlgorithms +ssh-rsa\n PubkeyAcceptedAlgorithms +ssh-rsa`;
|
host = `ssh.github.com\n Port 443\n HostkeyAlgorithms +ssh-rsa\n PubkeyAcceptedAlgorithms +ssh-rsa`;
|
||||||
}
|
}
|
||||||
const proxyStr = proxy ? ` ProxyCommand nc -v -x ${proxy} %h %p\n` : '';
|
const proxyStr = proxy ? ` ProxyCommand nc -v -x ${proxy} %h %p\n` : '';
|
||||||
return `Host ${alias}\n Hostname ${host}\n IdentityFile ${this.sshPath}/${alias}\n StrictHostKeyChecking no\n${proxyStr}`;
|
const config = `Host ${alias}\n Hostname ${host}\n IdentityFile ${this.sshPath}/${alias}\n StrictHostKeyChecking no\n${proxyStr}`;
|
||||||
}
|
fs.writeFileSync(`${this.sshPath}/${alias}.config`, config, { encoding: 'utf8' });
|
||||||
|
|
||||||
private generateSshConfig(configs: string[]) {
|
|
||||||
try {
|
|
||||||
fs.writeFileSync(this.sshConfigFilePath, configs.join('\n'), {
|
|
||||||
encoding: 'utf8',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
this.logger.error('写入ssh配置文件失败', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeSshConfig(alias: string) {
|
private removeSshConfig(alias: string) {
|
||||||
try {
|
try {
|
||||||
const configRegx = this.getConfigRegx(alias);
|
const filePath = path.join(this.sshPath, `${alias}.config`);
|
||||||
const data = fs
|
if (existsSync(filePath)) {
|
||||||
.readFileSync(this.sshConfigFilePath, { encoding: 'utf8' })
|
fs.unlinkSync(filePath);
|
||||||
.replace(configRegx, '')
|
}
|
||||||
.replace(/\n[\n]+/g, '\n');
|
|
||||||
fs.writeFileSync(this.sshConfigFilePath, data, {
|
|
||||||
encoding: 'utf8',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`删除ssh配置文件${alias}失败`, error);
|
this.logger.error(`删除ssh配置文件${alias}失败`, error);
|
||||||
}
|
}
|
||||||
|
@ -87,32 +78,27 @@ export default class SshKeyService {
|
||||||
proxy?: string,
|
proxy?: string,
|
||||||
): void {
|
): void {
|
||||||
this.generatePrivateKeyFile(alias, key);
|
this.generatePrivateKeyFile(alias, key);
|
||||||
const config = this.generateSingleSshConfig(alias, host, proxy);
|
this.generateSingleSshConfig(alias, host, proxy);
|
||||||
this.removeSshConfig(alias);
|
|
||||||
this.generateSshConfig([config]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeSSHKey(alias: string, host: string, proxy?: string): void {
|
public removeSSHKey(alias: string, host: string, proxy?: string): void {
|
||||||
this.removePrivateKeyFile(alias);
|
this.removePrivateKeyFile(alias);
|
||||||
const config = this.generateSingleSshConfig(alias, host, proxy);
|
this.removeSshConfig(alias);
|
||||||
this.removeSshConfig(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSshConfig(docs: Subscription[]) {
|
public setSshConfig(docs: Subscription[]) {
|
||||||
let result = [];
|
|
||||||
for (const doc of docs) {
|
for (const doc of docs) {
|
||||||
if (doc.type === 'private-repo' && doc.pull_type === 'ssh-key') {
|
if (doc.type === 'private-repo' && doc.pull_type === 'ssh-key') {
|
||||||
const { alias, proxy } = doc;
|
const { alias, proxy } = doc;
|
||||||
const { host } = formatUrl(doc);
|
const { host } = formatUrl(doc);
|
||||||
this.removePrivateKeyFile(alias);
|
this.removePrivateKeyFile(alias);
|
||||||
|
this.removeSshConfig(alias);
|
||||||
this.generatePrivateKeyFile(
|
this.generatePrivateKeyFile(
|
||||||
alias,
|
alias,
|
||||||
(doc.pull_option as any).private_key,
|
(doc.pull_option as any).private_key,
|
||||||
);
|
);
|
||||||
const config = this.generateSingleSshConfig(alias, host, proxy);
|
this.generateSingleSshConfig(alias, host, proxy);
|
||||||
result.push(config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.generateSshConfig(result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5930
pnpm-lock.yaml
5930
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user