forked from carlos8f/ssh-keygen2
-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
92 lines (87 loc) · 2.67 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import childProcess from "child_process";
import path from "path";
import os from "os";
import crypto from "crypto";
import fs from "fs";
const tmpDir = os.tmpdir();
export default (opts, cb) => {
if (typeof opts === "function") {
cb = opts;
opts = {};
}
opts = opts || {};
let stderr = "";
let stdout = "";
let overwriteRefused = false;
const location = opts.location || path.join(tmpDir, crypto.randomBytes(16).toString("hex"));
const args = [];
const ret = {};
if (opts.keep) {
ret.path = location;
}
if (opts.type) {
args.push("-t", opts.type);
}
if (opts.bits) {
args.push("-b", opts.bits);
}
args.push("-C", opts.comment || "");
args.push("-N", opts.passphrase || opts.password || "");
args.push("-f", location);
args.push("-m", "PEM");
const proc = childProcess.spawn("ssh-keygen", args);
proc.stderr.on("data", (data) => {
stderr += data;
});
proc.stdout.on("data", (data) => {
stdout += data;
// check for the case where we are trying to overwrite a file
if (stdout.indexOf("already exists") >= 0 && stdout.indexOf("Overwrite") >= 0) {
proc.stdin.write("n\n"); // send a "No" which should refuse to overwrite an existing key
overwriteRefused = true;
}
});
proc.on("exit", () => {
if (overwriteRefused) {
return cb(new Error("Key not generated because it would overwrite an existing file"));
}
return fs.readFile(location, { encoding: "ascii" }, (privateErr, privateKey) => {
if (privateErr && privateErr.code !== "ENOENT") {
return cb(privateErr);
}
if (!privateKey) {
return cb(new Error(stderr));
}
ret.private = privateKey;
return fs.readFile(`${location}.pub`, { encoding: "ascii" }, (publicErr, publicKey) => {
if (publicErr && publicErr.code !== "ENOENT") {
return cb(publicErr);
}
if (!publicKey) {
return cb(new Error(stderr));
}
ret.public = publicKey;
let match = stdout.match(/fingerprint is:\r?\n([^\r\n]+)\r?\n/);
if (match) ret.fingerprint = match[1].trim();
match = stdout.match(/randomart image is:\r?\n([\s\S]+)/);
if (match) {
ret.randomart = match[1].trim();
}
if (opts.keep) {
return cb(null, ret);
}
return fs.unlink(location, (unlinkPrivateErr) => {
if (unlinkPrivateErr) {
return cb(unlinkPrivateErr);
}
return fs.unlink(`${location}.pub`, (unlinkPublicErr) => {
if (unlinkPublicErr) {
return cb(unlinkPublicErr);
}
return cb(null, ret);
});
});
});
});
});
};