Skip to content

Commit

Permalink
Merge pull request #3 from starxg/dev
Browse files Browse the repository at this point in the history
1.0.2
  • Loading branch information
starxg committed Apr 8, 2021
2 parents 958aca2 + 47ca418 commit 5cdcad1
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 35 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Sync Config

### For the Terminus terminal
### For the [Terminus](https://github.com/Eugeny/terminus) terminal

This plugin can Sync configuration files to GitHub Gist or Gitee Gist.

![](./screenshot.png)

---

Like my work?

[![ko-fi](https://www.ko-fi.com/img/donate_sm.png)](https://ko-fi.com/huangxingguang)
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "terminus-sync-config",
"version": "1.0.1",
"version": "1.0.2",
"description": "Sync configuration files to GitHub Gist or Gitee Gist",
"keywords": [
"terminus-plugin"
Expand Down Expand Up @@ -44,7 +44,8 @@
"typescript": "^4.2.3",
"webpack": "^5.24.4",
"webpack-cli": "^4.5.0",
"axios": "^0.21.1"
"axios": "^0.21.1",
"keytar": "^7.6.0"
},
"peerDependencies": {
"@angular/core": "^4.0.1"
Expand Down
64 changes: 47 additions & 17 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,41 @@
import axios, { AxiosResponse } from "axios";

function resolveGist(response: AxiosResponse): any {
if (response.data.files["config.json"] && response.data.files["config.json"].content) {
return response.data.files["config.json"].content;
function resolveGist(response: AxiosResponse): Map<string, string> {

const files = response.data.files;

if (!files || Object.keys(files).length < 1) throw 'the config file is bad.';

const result = new Map<string, string>();

Reflect.ownKeys(files).forEach(e => {
const cnt = files[e].content;
if (cnt) {
result.set(e as string, cnt);
}
});

return result;
}

function toFiles(configs: Map<string, string>) {
const files = {};
for (const c of configs.keys()) {
files[c] = {
content: configs.get(c)
};
}
throw 'the config file is bad.';

return files;
}

async function syncGitee(token: string, gist: string, config: string): Promise<string> {
async function syncGitee(token: string, gist: string, configs: Map<string, string>): Promise<string> {
const url = gist ? `https://gitee.com/api/v5/gists/${gist}` : "https://gitee.com/api/v5/gists";


const data = {
access_token: token,
files: {
"config.json": { content: config }
},
files: toFiles(configs),
description: "sync terminus config",
public: false,
id: gist || ''
Expand Down Expand Up @@ -43,14 +65,12 @@ async function syncGitee(token: string, gist: string, config: string): Promise<s

}

async function syncGithub(token: string, gist: string, config: string): Promise<any> {

async function syncGithub(token: string, gist: string, configs: Map<string, string>): Promise<any> {

const url = gist ? `https://api.github.com/gists/${gist}` : "https://api.github.com/gists";

const data = {
files: {
"config.json": { content: config }
},
files: toFiles(configs),
description: "sync terminus config",
public: false
};
Expand Down Expand Up @@ -81,13 +101,13 @@ async function syncGithub(token: string, gist: string, config: string): Promise<
});
}

export function syncGist(type: string, token: string, gist: string, config: string): Promise<string> {
export function syncGist(type: string, token: string, gist: string, configs: Map<string, string>): Promise<string> {
return new Promise(async (resolve, reject) => {
try {
if (type === 'Gitee') {
resolve(await syncGitee(token, gist, config));
resolve(await syncGitee(token, gist, configs));
} else if (type === 'GitHub') {
resolve(await syncGithub(token, gist, config));
resolve(await syncGithub(token, gist, configs));
} else {
throw "unknown the type " + type;
}
Expand All @@ -97,7 +117,7 @@ export function syncGist(type: string, token: string, gist: string, config: stri
});
}

export function getGist(type: string, token: string, gist: string): Promise<string> {
export function getGist(type: string, token: string, gist: string): Promise<Map<string, string>> {

const isGithub = type === 'GitHub';
const url = isGithub ? `https://api.github.com/gists/${gist}` : `https://gitee.com/api/v5/gists/${gist}`;
Expand Down Expand Up @@ -130,4 +150,14 @@ export function getGist(type: string, token: string, gist: string): Promise<stri
}
}
});
}


export class Connection {
host: string;
port?: number;
user: string;
auth?: {
password: string;
};
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Component, OnInit } from '@angular/core'
import { ConfigService, ElectronService, } from 'terminus-core'
import { ToastrService } from 'ngx-toastr'
import { getGist, syncGist } from 'api';
import { Connection, getGist, syncGist } from 'api';
import { PasswordStorageService } from 'services/PasswordStorage.service';


/** @hidden */
@Component({
template: require('./settingsTab.component.pug'),
template: require('./SettingsTab.component.pug'),
})
export class SyncConfigSettingsTabComponent implements OnInit {
private isUploading: boolean = false;
Expand All @@ -15,6 +17,7 @@ export class SyncConfigSettingsTabComponent implements OnInit {
public config: ConfigService,
private toastr: ToastrService,
private electron: ElectronService,
private passwordStorage: PasswordStorageService,
) {
}

Expand Down Expand Up @@ -64,18 +67,38 @@ export class SyncConfigSettingsTabComponent implements OnInit {

try {
if (isUploading) {
this.config.store.syncConfig.gist = await syncGist(type, token, gistId, this.config.readRaw());

const configs = new Map<string, string>();
// config file
configs.set('config.json', this.config.readRaw());
// ssh password
configs.set('ssh.auth.json', JSON.stringify(await this.getSSHPluginAllPasswordInfos()))
this.config.store.syncConfig.gist = await syncGist(type, token, gistId, configs);

} else {

const result = await getGist(type, token, gistId);
this.config.writeRaw(result);

if (result.get('config.json')) {
this.config.writeRaw(result.get('config.json'));
}

if (result.get('ssh.auth.json')) {
await this.saveSSHPluginAllPasswordInfos(JSON.parse(result.get('ssh.auth.json')) as Connection[]);
}


if (this.config.store.syncConfig.gist !== gistId) {
this.config.store.syncConfig.gist = gistId;
}
}

this.toastr.info('Sync succeeded', null, {
timeOut: 1500
});

this.config.store.syncConfig.lastSyncTime = this.dateFormat(new Date);

} catch (error) {
this.toastr.error(error);
} finally {
Expand All @@ -90,7 +113,51 @@ export class SyncConfigSettingsTabComponent implements OnInit {
if (type === 'GitHub') {
this.electron.shell.openExternal('https://gist.github.com/' + gist)
}
}

async saveSSHPluginAllPasswordInfos(conns: Connection[]) {
if (conns.length < 1) return;

for (const conn of conns) {
try {
await this.passwordStorage.savePassword(conn);
} catch (error) {
console.error(conn, error);
}
}

}

getSSHPluginAllPasswordInfos(): Promise<Connection[]> {

return new Promise(async (resolve) => {

const connections = this.config.store.ssh.connections;
if (!(connections instanceof Array) || connections.length < 1) {
resolve([]);
return;
}

const infos = [];
for (const connect of connections) {
try {
const { host, port, user } = connect;
const pwd = await this.passwordStorage.loadPassword({ host, port, user });
if (!pwd) continue;
infos.push({
host, port, user,
auth: {
password: pwd
}
});
} catch (error) {
console.error(connect, error);
}
}

resolve(infos);

});
}

}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { NgModule } from '@angular/core'
import { SyncConfigSettingsTabComponent } from 'settingsTab.component';
import { SettingsTabProvider } from 'terminus-settings'
import { SyncConfigSettingsTabProvider } from './settings'
import { CommonModule } from '@angular/common'
import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ConfigProvider } from 'terminus-core';
import { SyncConfigProvider } from 'config';
import { SyncConfigSettingsTabComponent } from 'components/settingsTab.component'

@NgModule({
imports: [
Expand Down
32 changes: 32 additions & 0 deletions src/services/PasswordStorage.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import { Connection } from 'api';
import * as keytar from 'keytar'


function getKey(conn: Connection) {
let key = `ssh@${conn.host}`
if (conn.port) {
key = `ssh@${conn.host}:${conn.port}`
}
return key;
}

/**
* https://github.com/Eugeny/terminus/blob/bd46b08c9d909603eca4f1ca149d9a2d0155117f/terminus-ssh/src/services/passwordStorage.service.ts
*/
@Injectable({ providedIn: 'root' })
export class PasswordStorageService {

async savePassword(conn: Connection): Promise<void> {
return keytar.setPassword(getKey(conn), conn.user, conn.auth.password)
}

async deletePassword(conn: Connection): Promise<void> {
await keytar.deletePassword(getKey(conn), conn.user)
}

async loadPassword(conn: Connection): Promise<string | null> {
return keytar.getPassword(getKey(conn), conn.user)
}

}
3 changes: 1 addition & 2 deletions src/settings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Injectable } from '@angular/core'
import { SyncConfigSettingsTabComponent } from 'settingsTab.component'
import { SyncConfigSettingsTabComponent } from 'components/settingsTab.component'
import { SettingsTabProvider } from 'terminus-settings'

@Injectable()
export class SyncConfigSettingsTabProvider extends SettingsTabProvider {
id = 'sync-config'
Expand Down
2 changes: 2 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ module.exports = {
]
},
externals: [
'keytar',
'axios',
'fs',
'ngx-toastr',
/^rxjs/,
Expand Down
Loading

0 comments on commit 5cdcad1

Please sign in to comment.