@yubion-dev-team/yubion-fido2-server-sdk-js
Version:
This project is an SDK to use YubiOn FIDO2 Server Service from Node.js.
207 lines • 8.16 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.AccessKeyAuthApiRequester = exports.DatetimeSignAuthApiRequester = exports.NonceSignAuthApiRequester = exports.SignAuthApiRequesterBase = exports.FssApiRequesterBase = void 0;
exports.createApiRequester = createApiRequester;
const yup = __importStar(require("yup"));
const axiosBase = __importStar(require("axios"));
const node_crypto_1 = require("node:crypto");
const fss_api_error_1 = require("../fss-api-error");
const set_cookie_parser_1 = require("set-cookie-parser");
function createApiRequester(config) {
switch (config.apiAuthType) {
case "NonceSignAuth":
return new NonceSignAuthApiRequester(config);
case "DatetimeSignAuth":
return new DatetimeSignAuthApiRequester(config);
case "AccessKeyAuth":
return new AccessKeyAuthApiRequester(config);
default:
throw new Error("bad auth type.");
}
}
class FssApiRequesterBase {
axiosBase;
config;
constructor(config) {
this.config = config;
//If you wish to use a proxy server, use the environment variable `http_proxy` or `https_proxy`.
this.axiosBase = axiosBase.create({
baseURL: config.endpoint,
timeout: 60000,
headers: {
"Accept": "application/json",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
"Content-Type": "application/json",
"User-Agent": config.agent,
},
});
}
async request(path, param, options) {
return (await this.requestWithCookieResponse(path, param, options)).response;
}
async requestWithCookieResponse(path, param, options) {
const schema = options?.schema;
const withAuth = options?.withAuth === undefined ? true : options?.withAuth;
const cookie = options?.cookie;
let result;
const body = Buffer.from(JSON.stringify(param));
const additionalHeaders = withAuth ? await this.getAdditionalHeaders(body) : {};
if (cookie) {
additionalHeaders["cookie"] = cookie;
}
try {
result = await this.axiosBase.post(path, body, { headers: additionalHeaders });
}
catch (ex) {
throw new fss_api_error_1.FssApiError("axios error", { cause: ex, appStatus: "COMMUNICATION_FAILED" });
}
if (result.status !== 200) {
throw new fss_api_error_1.FssApiError("bad server response code.", { appStatus: "COMMUNICATION_FAILED", appSubStatus: { info: { httpStatus: result.status, } } });
}
let resData;
try {
if (typeof (result.data) === 'string') {
resData = JSON.parse(result.data);
}
else {
resData = result.data;
}
}
catch (ex) {
throw new fss_api_error_1.FssApiError("bad json response.", { cause: ex, appStatus: "COMMUNICATION_FAILED" });
}
if (resData.appStatus != "OK") {
throw new fss_api_error_1.FssApiError("server response:" + resData.appStatus, { appStatus: resData.appStatus, appSubStatus: resData.appSubStatus });
}
let response;
if (schema) {
response = schema.cast(resData.data);
}
else {
response = resData.data;
}
let respCookie = undefined;
if (result.headers["set-cookie"]) {
respCookie = (0, set_cookie_parser_1.parse)(result.headers["set-cookie"], { map: false }).map(c => c.name + "=" + c.value).join("; ");
}
const ret = {
cookie: respCookie,
response,
};
return ret;
}
async getAdditionalHeaders(body) {
return {
"X-Fss-Rp-Id": this.config.rpId,
"X-Fss-Api-Auth-Id": this.config.apiAuthId,
};
}
}
exports.FssApiRequesterBase = FssApiRequesterBase;
const keyPrm = {
name: "ECDSA",
namedCurve: "P-256",
};
class SignAuthApiRequesterBase extends FssApiRequesterBase {
privateKey;
constructor(config) {
super(config);
}
async getPrivateKey() {
if (!this.privateKey) {
this.privateKey = await crypto.subtle.importKey("pkcs8", Buffer.from(this.config.secretKey, "base64url"), keyPrm, true, ["sign"]);
}
return this.privateKey;
}
async getAdditionalHeaders(body) {
const key = await this.getPrivateKey();
const headers = await super.getAdditionalHeaders(body);
const signTargetInfo = await this.getSignInfo(body);
const bodyHash = await (0, node_crypto_1.createHash)("SHA-256").update(body).digest();
const signTarget = Buffer.concat([signTargetInfo.signTargetPrefix, bodyHash]);
const signature = await crypto.subtle.sign({ ...keyPrm, hash: "SHA-256" }, key, signTarget);
headers["X-Fss-Auth-Signature"] = Buffer.from(signature).toString("base64url");
headers["X-Fss-Auth-Body-Hash"] = bodyHash.toString("base64url");
Object.keys(signTargetInfo.additionalHeaders).forEach((x) => headers[x] = signTargetInfo.additionalHeaders[x]);
return headers;
}
}
exports.SignAuthApiRequesterBase = SignAuthApiRequesterBase;
class NonceSignAuthApiRequester extends SignAuthApiRequesterBase {
constructor(config) {
super(config);
}
async getSignInfo(body) {
const nonceResp = await this.request("getNonce", {}, { schema: yup.object().shape({ nonce: yup.string() }), withAuth: false });
return {
signTargetPrefix: Buffer.from(nonceResp.nonce, "utf-8"),
additionalHeaders: {
"X-Fss-Auth-Nonce": nonceResp.nonce,
}
};
}
}
exports.NonceSignAuthApiRequester = NonceSignAuthApiRequester;
class DatetimeSignAuthApiRequester extends SignAuthApiRequesterBase {
constructor(config) {
super(config);
}
async getSignInfo(body) {
const now = (new Date()).toISOString();
return {
signTargetPrefix: Buffer.from(now, "utf-8"),
additionalHeaders: {
"X-Fss-Auth-Request-Time": now,
}
};
}
}
exports.DatetimeSignAuthApiRequester = DatetimeSignAuthApiRequester;
class AccessKeyAuthApiRequester extends FssApiRequesterBase {
constructor(config) {
super(config);
}
async getAdditionalHeaders(body) {
const headers = await super.getAdditionalHeaders(body);
return {
...headers,
"X-Fss-Auth-Access-Key": this.config.secretKey,
};
}
}
exports.AccessKeyAuthApiRequester = AccessKeyAuthApiRequester;
//# sourceMappingURL=fss-api-requester.js.map