第一次
This commit is contained in:
426
src/user.ts
426
src/user.ts
@@ -1,214 +1,214 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import DevstarAPIHandler from './devstar-api';
|
||||
import { showErrorNotification } from './utils';
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
createHash
|
||||
} = require('node:crypto');
|
||||
const sshpk = require('sshpk');
|
||||
|
||||
export default class User {
|
||||
private context: vscode.ExtensionContext;
|
||||
private username: string | undefined;
|
||||
private userToken: string | undefined;
|
||||
private usernameKey: string = 'devstarUsername'
|
||||
private userTokenKey: string = 'devstarUserToken'
|
||||
private localUserPrivateKeyPath: string = ''
|
||||
private devstarHostname: string;
|
||||
|
||||
constructor(context: vscode.ExtensionContext) {
|
||||
this.context = context;
|
||||
this.username = this.context.globalState.get(this.usernameKey);
|
||||
this.userToken = this.context.globalState.get(this.userTokenKey);
|
||||
|
||||
// 提取devstar domain的主域名,用于本地ssh key的命名
|
||||
let devstarDomainFromConfig: string | undefined;
|
||||
let devstarDomainURL: string;
|
||||
devstarDomainFromConfig = vscode.workspace.getConfiguration('devstar').get('devstarDomain')
|
||||
// 如果没有配置devstar domain,则默认domain为https://devstar.cn
|
||||
devstarDomainURL = (devstarDomainFromConfig === undefined || devstarDomainFromConfig === "") ? 'https://devstar.cn' : devstarDomainFromConfig;
|
||||
let parsedUrl = new URL(devstarDomainURL);
|
||||
this.devstarHostname = parsedUrl.hostname.replace(/\./g, '_'); //提取hostname,并用下划线替换.
|
||||
}
|
||||
|
||||
public async login(token: string, username: string) {
|
||||
const devstarAPIHandler = new DevstarAPIHandler()
|
||||
|
||||
try {
|
||||
const res = await devstarAPIHandler.verifyToken(token, username)
|
||||
if (!res) {
|
||||
throw new Error('Token verification failed')
|
||||
}
|
||||
|
||||
// token与用户名验证通过
|
||||
// 插件登录:存储token与用户名
|
||||
this.setUserTokenToLocal(token)
|
||||
this.setUsernameToLocal(username)
|
||||
|
||||
// 检查本地是否有用户所属公钥,没有则创建
|
||||
if (!this.existUserPublicKey()) {
|
||||
await this.createUserSSHKey()
|
||||
|
||||
// 上传公钥
|
||||
const uploadResult = await devstarAPIHandler.uploadUserPublicKey(this)
|
||||
if (uploadResult !== 'ok') {
|
||||
throw new Error('Upload user public key failed')
|
||||
}
|
||||
}
|
||||
|
||||
vscode.window.showInformationMessage(vscode.l10n.t('User login successfully!'))
|
||||
return 'ok'
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await showErrorNotification('用户登录失败!')
|
||||
return 'login failed'
|
||||
}
|
||||
}
|
||||
|
||||
public logout() {
|
||||
this.setUserTokenToLocal("")
|
||||
this.setUsernameToLocal("")
|
||||
vscode.window.showInformationMessage(vscode.l10n.t("User has logged out!"))
|
||||
}
|
||||
|
||||
public isLogged() {
|
||||
var existUsername = false;
|
||||
var existUserToken = false;
|
||||
if (this.username != undefined && this.username != '') {
|
||||
existUsername = true;
|
||||
}
|
||||
if (this.userToken != undefined && this.userToken != '') {
|
||||
existUserToken = true;
|
||||
}
|
||||
|
||||
if (existUsername && existUserToken) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public getUsernameFromLocal(): string | undefined {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public getUserTokenFromLocal(): string | undefined {
|
||||
return this.userToken;
|
||||
}
|
||||
|
||||
public setUsernameToLocal(username: string) {
|
||||
this.context.globalState.update(this.usernameKey, username);
|
||||
this.username = username;
|
||||
if (username !== "") {
|
||||
console.log('Username has been stored.')
|
||||
} else {
|
||||
console.log('Username has been cleaned up.')
|
||||
}
|
||||
}
|
||||
|
||||
public setUserTokenToLocal(userToken: string) {
|
||||
this.context.globalState.update(this.userTokenKey, userToken)
|
||||
this.userToken = userToken
|
||||
if (userToken !== "") {
|
||||
console.log('Token has been stored.');
|
||||
} else {
|
||||
console.log('Token has been cleaned up.')
|
||||
}
|
||||
}
|
||||
|
||||
public updateLocalUserPrivateKeyPath(localUserPrivateKeyPath: string) {
|
||||
this.context.globalState.update('localUserPrivateKeyPath', localUserPrivateKeyPath)
|
||||
}
|
||||
|
||||
public getLocalUserPrivateKeyPath(): undefined | string {
|
||||
return this.context.globalState.get('localUserPrivateKeyPath')
|
||||
}
|
||||
|
||||
public getUserPrivateKeyPath(): string {
|
||||
if (!this.isLogged) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}`)
|
||||
}
|
||||
|
||||
public getUserPublicKeyPath(): string {
|
||||
if (!this.isLogged) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}.pub`)
|
||||
}
|
||||
|
||||
public existUserPublicKey(): boolean {
|
||||
const userPublicKeyPath = this.getUserPublicKeyPath();
|
||||
return fs.existsSync(userPublicKeyPath)
|
||||
}
|
||||
|
||||
public existUserPrivateKey(): boolean {
|
||||
const userPrivateKeyPath = this.getUserPrivateKeyPath();
|
||||
return fs.existsSync(userPrivateKeyPath)
|
||||
}
|
||||
|
||||
public getUserPublicKey(): string {
|
||||
const userPublicKeyPath = this.getUserPublicKeyPath();
|
||||
const userPublicKey = fs.readFileSync(userPublicKeyPath, 'utf-8');
|
||||
// remove `\r` `\n`
|
||||
const trimmedDefaultPublicKey = userPublicKey.replace(/[\r\n]/g, "");
|
||||
return trimmedDefaultPublicKey;
|
||||
}
|
||||
|
||||
public getUserPrivateKey(): string {
|
||||
const userPrivateKey = this.getUserPrivateKeyPath();
|
||||
return fs.readFileSync(userPrivateKey, 'utf-8');
|
||||
}
|
||||
|
||||
public async createUserSSHKey() {
|
||||
if (this.existUserPublicKey() && this.existUserPrivateKey()) {
|
||||
// if both public and private key exists, stop
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
publicKey,
|
||||
privateKey,
|
||||
} = await generateKeyPairSync('rsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem',
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem',
|
||||
},
|
||||
});
|
||||
const publicKeyFingerprint = sshpk.parseKey(publicKey, 'pem').toString('ssh');
|
||||
const publicKeyStr = publicKeyFingerprint; // public key is public key fingerprint
|
||||
const privateKeyStr = privateKey;
|
||||
|
||||
try {
|
||||
// 确保公/私钥目录存在
|
||||
const publicKeyDir = path.dirname(this.getUserPublicKeyPath())
|
||||
if (!fs.existsSync(publicKeyDir)) {
|
||||
console.log(`Directory ${publicKeyDir} does not exist, creating it...`);
|
||||
// 公钥与私钥的目录一样,所以只用创建一次
|
||||
fs.mkdirSync(publicKeyDir, {recursive: true})
|
||||
}
|
||||
|
||||
fs.writeFileSync(this.getUserPublicKeyPath(), publicKeyStr);
|
||||
fs.writeFileSync(this.getUserPrivateKeyPath(), privateKeyStr);
|
||||
// limit the permission of private key to prevent that the private key not works
|
||||
fs.chmodSync(this.getUserPrivateKeyPath(), 0o600)
|
||||
console.log(`User's ssh key has been created.`)
|
||||
// 更新local user private key path
|
||||
this.updateLocalUserPrivateKeyPath(this.getUserPrivateKeyPath())
|
||||
console.log(`Update local user private key path.`)
|
||||
} catch (error) {
|
||||
console.error(`Failed to write public/private key into the user(${this.username}) ssh public/key file: `, error);
|
||||
}
|
||||
}
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import DevstarAPIHandler from './devstar-api';
|
||||
import { showErrorNotification } from './utils';
|
||||
const {
|
||||
generateKeyPairSync,
|
||||
createHash
|
||||
} = require('node:crypto');
|
||||
const sshpk = require('sshpk');
|
||||
|
||||
export default class User {
|
||||
private context: vscode.ExtensionContext;
|
||||
private username: string | undefined;
|
||||
private userToken: string | undefined;
|
||||
private usernameKey: string = 'devstarUsername'
|
||||
private userTokenKey: string = 'devstarUserToken'
|
||||
private localUserPrivateKeyPath: string = ''
|
||||
private devstarHostname: string;
|
||||
|
||||
constructor(context: vscode.ExtensionContext) {
|
||||
this.context = context;
|
||||
this.username = this.context.globalState.get(this.usernameKey);
|
||||
this.userToken = this.context.globalState.get(this.userTokenKey);
|
||||
|
||||
// 提取devstar domain的主域名,用于本地ssh key的命名
|
||||
let devstarDomainFromConfig: string | undefined;
|
||||
let devstarDomainURL: string;
|
||||
devstarDomainFromConfig = vscode.workspace.getConfiguration('devstar').get('devstarDomain')
|
||||
// 如果没有配置devstar domain,则默认domain为https://devstar.cn
|
||||
devstarDomainURL = (devstarDomainFromConfig === undefined || devstarDomainFromConfig === "") ? 'https://devstar.cn' : devstarDomainFromConfig;
|
||||
let parsedUrl = new URL(devstarDomainURL);
|
||||
this.devstarHostname = parsedUrl.hostname.replace(/\./g, '_'); //提取hostname,并用下划线替换.
|
||||
}
|
||||
|
||||
public async login(token: string, username: string) {
|
||||
const devstarAPIHandler = new DevstarAPIHandler()
|
||||
|
||||
try {
|
||||
const res = await devstarAPIHandler.verifyToken(token, username)
|
||||
if (!res) {
|
||||
throw new Error('Token verification failed')
|
||||
}
|
||||
|
||||
// token与用户名验证通过
|
||||
// 插件登录:存储token与用户名
|
||||
this.setUserTokenToLocal(token)
|
||||
this.setUsernameToLocal(username)
|
||||
|
||||
// 检查本地是否有用户所属公钥,没有则创建
|
||||
if (!this.existUserPublicKey()) {
|
||||
await this.createUserSSHKey()
|
||||
|
||||
// 上传公钥
|
||||
const uploadResult = await devstarAPIHandler.uploadUserPublicKey(this)
|
||||
if (uploadResult !== 'ok') {
|
||||
throw new Error('Upload user public key failed')
|
||||
}
|
||||
}
|
||||
|
||||
vscode.window.showInformationMessage(vscode.l10n.t('User login successfully!'))
|
||||
return 'ok'
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
await showErrorNotification('用户登录失败!')
|
||||
return 'login failed'
|
||||
}
|
||||
}
|
||||
|
||||
public logout() {
|
||||
this.setUserTokenToLocal("")
|
||||
this.setUsernameToLocal("")
|
||||
vscode.window.showInformationMessage(vscode.l10n.t("User has logged out!"))
|
||||
}
|
||||
|
||||
public isLogged() {
|
||||
var existUsername = false;
|
||||
var existUserToken = false;
|
||||
if (this.username != undefined && this.username != '') {
|
||||
existUsername = true;
|
||||
}
|
||||
if (this.userToken != undefined && this.userToken != '') {
|
||||
existUserToken = true;
|
||||
}
|
||||
|
||||
if (existUsername && existUserToken) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public getUsernameFromLocal(): string | undefined {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public getUserTokenFromLocal(): string | undefined {
|
||||
return this.userToken;
|
||||
}
|
||||
|
||||
public setUsernameToLocal(username: string) {
|
||||
this.context.globalState.update(this.usernameKey, username);
|
||||
this.username = username;
|
||||
if (username !== "") {
|
||||
console.log('Username has been stored.')
|
||||
} else {
|
||||
console.log('Username has been cleaned up.')
|
||||
}
|
||||
}
|
||||
|
||||
public setUserTokenToLocal(userToken: string) {
|
||||
this.context.globalState.update(this.userTokenKey, userToken)
|
||||
this.userToken = userToken
|
||||
if (userToken !== "") {
|
||||
console.log('Token has been stored.');
|
||||
} else {
|
||||
console.log('Token has been cleaned up.')
|
||||
}
|
||||
}
|
||||
|
||||
public updateLocalUserPrivateKeyPath(localUserPrivateKeyPath: string) {
|
||||
this.context.globalState.update('localUserPrivateKeyPath', localUserPrivateKeyPath)
|
||||
}
|
||||
|
||||
public getLocalUserPrivateKeyPath(): undefined | string {
|
||||
return this.context.globalState.get('localUserPrivateKeyPath')
|
||||
}
|
||||
|
||||
public getUserPrivateKeyPath(): string {
|
||||
if (!this.isLogged) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}`)
|
||||
}
|
||||
|
||||
public getUserPublicKeyPath(): string {
|
||||
if (!this.isLogged) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}.pub`)
|
||||
}
|
||||
|
||||
public existUserPublicKey(): boolean {
|
||||
const userPublicKeyPath = this.getUserPublicKeyPath();
|
||||
return fs.existsSync(userPublicKeyPath)
|
||||
}
|
||||
|
||||
public existUserPrivateKey(): boolean {
|
||||
const userPrivateKeyPath = this.getUserPrivateKeyPath();
|
||||
return fs.existsSync(userPrivateKeyPath)
|
||||
}
|
||||
|
||||
public getUserPublicKey(): string {
|
||||
const userPublicKeyPath = this.getUserPublicKeyPath();
|
||||
const userPublicKey = fs.readFileSync(userPublicKeyPath, 'utf-8');
|
||||
// remove `\r` `\n`
|
||||
const trimmedDefaultPublicKey = userPublicKey.replace(/[\r\n]/g, "");
|
||||
return trimmedDefaultPublicKey;
|
||||
}
|
||||
|
||||
public getUserPrivateKey(): string {
|
||||
const userPrivateKey = this.getUserPrivateKeyPath();
|
||||
return fs.readFileSync(userPrivateKey, 'utf-8');
|
||||
}
|
||||
|
||||
public async createUserSSHKey() {
|
||||
if (this.existUserPublicKey() && this.existUserPrivateKey()) {
|
||||
// if both public and private key exists, stop
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
publicKey,
|
||||
privateKey,
|
||||
} = await generateKeyPairSync('rsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem',
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem',
|
||||
},
|
||||
});
|
||||
const publicKeyFingerprint = sshpk.parseKey(publicKey, 'pem').toString('ssh');
|
||||
const publicKeyStr = publicKeyFingerprint; // public key is public key fingerprint
|
||||
const privateKeyStr = privateKey;
|
||||
|
||||
try {
|
||||
// 确保公/私钥目录存在
|
||||
const publicKeyDir = path.dirname(this.getUserPublicKeyPath())
|
||||
if (!fs.existsSync(publicKeyDir)) {
|
||||
console.log(`Directory ${publicKeyDir} does not exist, creating it...`);
|
||||
// 公钥与私钥的目录一样,所以只用创建一次
|
||||
fs.mkdirSync(publicKeyDir, {recursive: true})
|
||||
}
|
||||
|
||||
fs.writeFileSync(this.getUserPublicKeyPath(), publicKeyStr);
|
||||
fs.writeFileSync(this.getUserPrivateKeyPath(), privateKeyStr);
|
||||
// limit the permission of private key to prevent that the private key not works
|
||||
fs.chmodSync(this.getUserPrivateKeyPath(), 0o600)
|
||||
console.log(`User's ssh key has been created.`)
|
||||
// 更新local user private key path
|
||||
this.updateLocalUserPrivateKeyPath(this.getUserPrivateKeyPath())
|
||||
console.log(`Update local user private key path.`)
|
||||
} catch (error) {
|
||||
console.error(`Failed to write public/private key into the user(${this.username}) ssh public/key file: `, error);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user