@microsoft/dev-tunnels-ssh-keys
Version:
SSH key import/export library for Dev Tunnels
113 lines • 4.09 kB
JavaScript
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
Object.defineProperty(exports, "__esModule", { value: true });
exports.KeyData = void 0;
/**
* Encapsulates formatted (serialized) key data and metadata.
*/
class KeyData {
constructor(keyType, data) {
/**
* Optional headers containing key metadata. In PEM encoding, the headers appear in
* plaintext before the base64-encoded key.
*/
this.headers = new Map();
this.keyType = keyType !== null && keyType !== void 0 ? keyType : '';
this.data = data !== null && data !== void 0 ? data : Buffer.alloc(0);
}
static tryDecodePem(input) {
const lines = input.split('\n').map((line) => line.trimRight());
while (lines.length > 0 && lines[lines.length - 1].length === 0) {
lines.splice(lines.length - 1, 1);
}
const beginMatch = lines[0].match(KeyData.beginRegex);
const endMatch = lines[lines.length - 1].match(KeyData.endRegex);
if (!beginMatch || !endMatch) {
return null;
}
const keyType = beginMatch[1];
if (endMatch[1] !== keyType) {
return null;
}
const headers = new Map();
let i = 1;
if (lines[i].includes(':')) {
for (; i < lines.length - 1 && lines[i].length > 0; i++) {
const headerMatch = lines[i].match(this.headerRegex);
if (headerMatch) {
const name = headerMatch[1];
let value = headerMatch[2];
while (value.endsWith('\\')) {
value = value.substr(0, value.length - 1);
value += lines[++i];
}
headers.set(name, value);
}
}
}
while (lines[i].length === 0) {
i++;
}
const base64Data = lines.slice(i, lines.length - 1).join('');
let data;
try {
data = Buffer.from(base64Data, 'base64');
}
catch (e) {
return null;
}
const keyData = new KeyData();
keyData.keyType = keyType;
keyData.headers = headers;
keyData.data = data;
return keyData;
}
static tryDecodePemBytes(input) {
const hyphen = '-'.charCodeAt(0);
if (input.length < 3 || input[0] !== hyphen || input[1] !== hyphen || input[2] !== hyphen) {
return null;
}
let inputString;
try {
inputString = input.toString('utf8');
}
catch (e) {
return null;
}
return KeyData.tryDecodePem(inputString);
}
encodePem() {
let s = `-----BEGIN ${this.keyType}-----\n`;
for (const [name, value] of this.headers) {
// TODO: Wrap the value with \ if it's long.
s += `${name}: ${value}\n`;
}
if (this.headers.size > 0) {
s += '\n';
}
const dataBase64 = this.data.toString('base64');
const lineLength = 64;
for (let offset = 0; offset < dataBase64.length; offset += lineLength) {
s += dataBase64.substr(offset, Math.min(lineLength, dataBase64.length - offset)) + '\n';
}
s += `-----END ${this.keyType}-----\n`;
return s;
}
encodePemBytes() {
return Buffer.from(this.encodePem(), 'utf8');
}
encodeSshPublicKey() {
const comment = this.headers.get('Comment');
return (this.keyType + ' ' + this.data.toString('base64') + (comment ? ' ' + comment : '') + '\n');
}
encodeSshPublicKeyBytes() {
return Buffer.from(this.encodeSshPublicKey(), 'utf8');
}
}
exports.KeyData = KeyData;
KeyData.beginRegex = /^-+ *BEGIN (\w+( \w+)*) *-+$/;
KeyData.endRegex = /^-+ *END (\w+( \w+)*) *-+$/;
KeyData.headerRegex = /^([\w-]+): (.*)$/;
//# sourceMappingURL=keyData.js.map
;