sui-direct
Version:
Decentralized version control system on SUI blockchain
142 lines (141 loc) • 6.18 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const os_1 = require("os");
const prompts_1 = __importDefault(require("prompts"));
const utils_1 = require("@mysten/sui/utils");
const fs_1 = require("fs");
const p2p_1 = __importDefault(require("./p2p"));
const colors_1 = require("../utils/colors");
class Auth extends p2p_1.default {
constructor(_) {
super();
this.connection = _.connection;
this.nodePeerID = _.nodePeerID;
this.peerID = _.peerID;
}
static async waitUntilAuthenticated(stream, token) {
// Send token message
await stream.sink(JSON.stringify({ token }));
// Wait for server to acknowledge token validation
const ackChunk = await stream.source.next();
const ack = JSON.parse(ackChunk.value.toString());
if (ack.status !== true) {
throw new Error(ack.message || "Token validation failed on server.");
}
}
async getUser() {
return new Promise(async (resolve, reject) => {
const unauthenticated = () => {
console.log(colors_1.colorize.errorIcon("You must be logged in to perform this action."));
return reject();
};
const tokenDir = `${(0, os_1.homedir)()}/.sui-direct/TOKEN`;
if (!(0, fs_1.existsSync)(tokenDir))
return unauthenticated();
const token = (0, fs_1.readFileSync)(tokenDir, "utf-8");
if (!token)
return unauthenticated();
const stream = await this.connection.newStream(this.VALIDATE_PROTOCOL);
const message = JSON.stringify({
token,
peerID: this.peerID.toString(),
});
await this.sink(stream, message);
const response = await this.parseChunk(stream);
if (response === null || response === void 0 ? void 0 : response.expired) {
this.logout();
console.log(colors_1.colorize.errorIcon("Session is expired. Please login again."));
return reject(response.error);
}
if ((response === null || response === void 0 ? void 0 : response.status) !== "ok") {
return unauthenticated();
}
return resolve({
data: response.decoded.data,
token,
});
});
}
async login(publicKey) {
// Get nonce from node
const nonceStream = await this.connection.newStream(this.NONCE_PROTOCOL);
const nonceMessage = JSON.stringify({
peerID: this.peerID.toString(),
});
await this.sink(nonceStream, nonceMessage);
const response = await this.parseChunk(nonceStream);
if (!(response === null || response === void 0 ? void 0 : response.nonce)) {
console.error(colors_1.colorize.errorIcon("Failed to get nonce from node."));
return;
}
// Get public key
if (!publicKey) {
const publicKeyInput = await (0, prompts_1.default)({
type: "text",
name: "publicKey",
message: "Please enter your SUI wallet address",
validate: (value) => (0, utils_1.isValidSuiAddress)(value) && value.trim() ? true : "Invalid SUI address",
});
publicKey = publicKeyInput.publicKey;
if (!publicKey) {
console.error(colors_1.colorize.errorIcon("Public key is required to authenticate."));
return;
}
}
// Instructions
console.log("\n");
console.log("Please go to the following URL to sign a message:");
console.log(`${colors_1.colorize.warning(`https://sui.direct/sign?nonce=${response.nonce}`)}${colors_1.colorize.reset()}\n\n`);
console.log("If you are using CLI wallet, please sign the message below:\n");
console.log(`${colors_1.colorize.highlight(`Welcome to sui.direct!\n\nSign this message to authenticate in the CLI.\n\nNonce: ${response.nonce}`)}${colors_1.colorize.reset()}`);
let validated = false;
let token;
while (!validated) {
const signatureInput = await (0, prompts_1.default)({
type: "text",
name: "signature",
message: "Paste the signature here",
validate: (value) => (value.length > 0 ? true : "Signature cannot be empty"),
});
const signature = signatureInput.signature;
if (signature === "exit" || signature === "quit") {
console.log(colors_1.colorize.error("Good bye!"));
return;
}
// Send the signature to the node for validation
const signatureStream = await this.connection.newStream(this.SIGNATURE_PROTOCOL);
const signatureMessage = JSON.stringify({
peerID: this.peerID.toString(),
publicKey: publicKey,
signature: signature,
});
await this.sink(signatureStream, signatureMessage);
const signatureResponse = await this.parseChunk(signatureStream);
if (signatureResponse === null || signatureResponse === void 0 ? void 0 : signatureResponse.error) {
console.log(colors_1.colorize.errorIcon(signatureResponse.error));
}
else {
token = signatureResponse.token;
validated = true;
}
}
// Store the token
(0, fs_1.writeFileSync)(`${(0, os_1.homedir)()}/.sui-direct/TOKEN`, token, {
encoding: "utf-8",
flag: "w+",
});
console.log(colors_1.colorize.successIcon("Successfully authenticated."));
}
logout() {
try {
(0, fs_1.rmSync)(`${(0, os_1.homedir)()}/.sui-direct/TOKEN`);
}
catch (e) {
// Ignore errors
}
}
}
exports.default = Auth;