mirror of
https://github.com/certd/certd.git
synced 2026-04-21 10:27:25 +08:00
feat: plugin-huawei
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { IsAccess, AccessInput } from "@certd/pipeline";
|
||||
|
||||
@IsAccess({
|
||||
name: "huawei",
|
||||
title: "华为云授权",
|
||||
desc: "",
|
||||
})
|
||||
export class HuaweiAccess {
|
||||
@AccessInput({
|
||||
title: "accessKeyId",
|
||||
component: {
|
||||
placeholder: "accessKeyId",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessKeyId = "";
|
||||
@AccessInput({
|
||||
title: "accessKeySecret",
|
||||
component: {
|
||||
placeholder: "accessKeySecret",
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessKeySecret = "";
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./huawei-access";
|
||||
@@ -0,0 +1,114 @@
|
||||
import _ from "lodash";
|
||||
import { CreateRecordOptions, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
|
||||
import { Autowire, ILogger } from "@certd/pipeline";
|
||||
import { HuaweiAccess } from "../access";
|
||||
import { HuaweiYunClient } from "../lib/client";
|
||||
|
||||
@IsDnsProvider({
|
||||
name: "huawei",
|
||||
title: "华为云",
|
||||
desc: "华为云DNS解析提供商",
|
||||
accessType: "huawei",
|
||||
})
|
||||
export class HuaweiDnsProvider implements IDnsProvider {
|
||||
client: any;
|
||||
@Autowire()
|
||||
access!: HuaweiAccess;
|
||||
@Autowire()
|
||||
logger!: ILogger;
|
||||
endpoint = "https://domains-external.myhuaweicloud.com";
|
||||
async onInit() {
|
||||
const access: any = this.access;
|
||||
this.client = new HuaweiYunClient(access);
|
||||
}
|
||||
|
||||
async getDomainList() {
|
||||
const url = `${this.endpoint}/v2/domains`;
|
||||
const ret = await this.client.request({
|
||||
url,
|
||||
method: "GET",
|
||||
});
|
||||
return ret.domains;
|
||||
}
|
||||
|
||||
async matchDomain(dnsRecord: string) {
|
||||
const list = await this.getDomainList();
|
||||
let domain = null;
|
||||
for (const item of list) {
|
||||
if (_.endsWith(dnsRecord, item.DomainName)) {
|
||||
domain = item.DomainName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!domain) {
|
||||
throw new Error("can not find Domain ," + dnsRecord);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
async getRecords(domain: string, rr: string, value: string) {
|
||||
const params: any = {
|
||||
RegionId: "cn-hangzhou",
|
||||
DomainName: domain,
|
||||
RRKeyWord: rr,
|
||||
ValueKeyWord: undefined,
|
||||
};
|
||||
if (value) {
|
||||
params.ValueKeyWord = value;
|
||||
}
|
||||
|
||||
const requestOption = {
|
||||
method: "POST",
|
||||
};
|
||||
|
||||
const ret = await this.client.request("DescribeDomainRecords", params, requestOption);
|
||||
return ret.DomainRecords.Record;
|
||||
}
|
||||
|
||||
async createRecord(options: CreateRecordOptions): Promise<any> {
|
||||
const { fullRecord, value, type } = options;
|
||||
this.logger.info("添加域名解析:", fullRecord, value);
|
||||
const domain = await this.matchDomain(fullRecord);
|
||||
const rr = fullRecord.replace("." + domain, "");
|
||||
|
||||
const params = {
|
||||
RegionId: "cn-hangzhou",
|
||||
DomainName: domain,
|
||||
RR: rr,
|
||||
Type: type,
|
||||
Value: value,
|
||||
// Line: 'oversea' // 海外
|
||||
};
|
||||
|
||||
const requestOption = {
|
||||
method: "POST",
|
||||
};
|
||||
|
||||
try {
|
||||
const ret = await this.client.request("AddDomainRecord", params, requestOption);
|
||||
this.logger.info("添加域名解析成功:", value, value, ret.RecordId);
|
||||
return ret.RecordId;
|
||||
} catch (e: any) {
|
||||
if (e.code === "DomainRecordDuplicate") {
|
||||
return;
|
||||
}
|
||||
this.logger.info("添加域名解析出错", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
async removeRecord(options: RemoveRecordOptions): Promise<any> {
|
||||
const { fullRecord, value, record } = options;
|
||||
const params = {
|
||||
RegionId: "cn-hangzhou",
|
||||
RecordId: record,
|
||||
};
|
||||
|
||||
const requestOption = {
|
||||
method: "POST",
|
||||
};
|
||||
|
||||
const ret = await this.client.request("DeleteDomainRecord", params, requestOption);
|
||||
this.logger.info("删除域名解析成功:", fullRecord, value, ret.RecordId);
|
||||
return ret.RecordId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import "./huawei-dns-provider";
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./access";
|
||||
export * from "./dns-provider";
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
# License
|
||||
|
||||
[The MIT License (MIT)](http://opensource.org/licenses/MIT)
|
||||
|
||||
Copyright (c) 2009-2013 Jeff Mott
|
||||
Copyright (c) 2013-2016 Evan Vosberg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
var signer = require("./signer");
|
||||
var https = require("https");
|
||||
var sig = new signer.Signer();
|
||||
//Set the AK/SK to sign and authenticate the request.
|
||||
sig.Key = "QTWAOYTTINDUT2QVKYUC";
|
||||
sig.Secret = "MFyfvK41ba2giqM7**********KGpownRZlmVmHc";
|
||||
|
||||
//The following example shows how to set the request URL and parameters to query a VPC list.
|
||||
//Specify a request method, such as GET, PUT, POST, DELETE, HEAD, and PATCH.
|
||||
//Set request host.
|
||||
//Set request URI.
|
||||
//Set parameters for the request URL.
|
||||
var r = new signer.HttpRequest("GET", "endpoint.example.com/v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs?limie=1");
|
||||
//Add header parameters, for example, x-domain-id for invoking a global service and x-project-id for invoking a project-level service.
|
||||
r.headers = { "Content-Type": "application/json" };
|
||||
//Add a body if you have specified the PUT or POST method. Special characters, such as the double quotation mark ("), contained in the body must be escaped.
|
||||
r.body = "";
|
||||
|
||||
var opt = sig.Sign(r);
|
||||
console.log(opt.headers["X-Sdk-Date"]);
|
||||
console.log(opt.headers["Authorization"]);
|
||||
|
||||
var req = https.request(opt, function (res) {
|
||||
console.log(res.statusCode);
|
||||
console.log("headers:", JSON.stringify(res.headers));
|
||||
res.on("data", function (chunk) {
|
||||
console.log(chunk.toString());
|
||||
});
|
||||
});
|
||||
|
||||
req.on("error", function (err) {
|
||||
console.log(err.message);
|
||||
});
|
||||
req.write(r.body);
|
||||
req.end();
|
||||
@@ -0,0 +1,501 @@
|
||||
// HWS API Gateway Signature
|
||||
(function (root, factory) {
|
||||
"use strict";
|
||||
|
||||
/*global define*/
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD
|
||||
define(["CryptoJS"], function (CryptoJS) {
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return CryptoJS.HmacSHA256(message, keyByte).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return CryptoJS.SHA256(body);
|
||||
},
|
||||
};
|
||||
return factory(crypto_wrapper);
|
||||
});
|
||||
} else if (typeof wx === "object") {
|
||||
// wechat
|
||||
var CryptoJS = require("./js/hmac-sha256.js");
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return CryptoJS.HmacSHA256(message, keyByte).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return CryptoJS.SHA256(body);
|
||||
},
|
||||
};
|
||||
module.exports = factory(crypto_wrapper);
|
||||
} else if (typeof module === "object" && module.exports) {
|
||||
// Node
|
||||
var crypto = require("crypto");
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return crypto.createHmac("SHA256", keyByte).update(message).digest().toString("hex");
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return crypto.createHash("SHA256").update(body).digest().toString("hex");
|
||||
},
|
||||
};
|
||||
module.exports = factory(crypto_wrapper);
|
||||
} else {
|
||||
// Browser
|
||||
var CryptoJS = root.CryptoJS;
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return CryptoJS.HmacSHA256(message, keyByte).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return CryptoJS.SHA256(body);
|
||||
},
|
||||
};
|
||||
root.signer = factory(crypto_wrapper);
|
||||
}
|
||||
})(this, function (crypto_wrapper) {
|
||||
"use strict";
|
||||
|
||||
var Algorithm = "SDK-HMAC-SHA256";
|
||||
var HeaderXDate = "X-Sdk-Date";
|
||||
var HeaderAuthorization = "Authorization";
|
||||
var HeaderContentSha256 = "x-sdk-content-sha256";
|
||||
|
||||
const hexTable = new Array(256);
|
||||
for (var i = 0; i < 256; ++i) hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
|
||||
|
||||
const noEscape = [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // 0 - 15
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // 16 - 31
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0, // 32 - 47
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // 48 - 63
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1, // 64 - 79
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1, // 80 - 95
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1, // 96 - 111
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0, // 112 - 127
|
||||
];
|
||||
|
||||
// function urlEncode is based on https://github.com/nodejs/node/blob/master/lib/querystring.js
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
function urlEncode(str) {
|
||||
if (typeof str !== "string") {
|
||||
if (typeof str === "object") str = String(str);
|
||||
else str += "";
|
||||
}
|
||||
var out = "";
|
||||
var lastPos = 0;
|
||||
|
||||
for (var i = 0; i < str.length; ++i) {
|
||||
var c = str.charCodeAt(i);
|
||||
|
||||
// ASCII
|
||||
if (c < 0x80) {
|
||||
if (noEscape[c] === 1) continue;
|
||||
if (lastPos < i) out += str.slice(lastPos, i);
|
||||
lastPos = i + 1;
|
||||
out += hexTable[c];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastPos < i) out += str.slice(lastPos, i);
|
||||
|
||||
// Multi-byte characters ...
|
||||
if (c < 0x800) {
|
||||
lastPos = i + 1;
|
||||
out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
|
||||
continue;
|
||||
}
|
||||
if (c < 0xd800 || c >= 0xe000) {
|
||||
lastPos = i + 1;
|
||||
out += hexTable[0xe0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3f)] + hexTable[0x80 | (c & 0x3f)];
|
||||
continue;
|
||||
}
|
||||
// Surrogate pair
|
||||
++i;
|
||||
|
||||
if (i >= str.length) throw new errors.URIError("ERR_INVALID_URI");
|
||||
|
||||
var c2 = str.charCodeAt(i) & 0x3ff;
|
||||
|
||||
lastPos = i + 1;
|
||||
c = 0x10000 + (((c & 0x3ff) << 10) | c2);
|
||||
out += hexTable[0xf0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3f)] + hexTable[0x80 | ((c >> 6) & 0x3f)] + hexTable[0x80 | (c & 0x3f)];
|
||||
}
|
||||
if (lastPos === 0) return str;
|
||||
if (lastPos < str.length) return out + str.slice(lastPos);
|
||||
return out;
|
||||
}
|
||||
|
||||
function HttpRequest(method, url, headers, body) {
|
||||
if (method === undefined) {
|
||||
this.method = "";
|
||||
} else {
|
||||
this.method = method;
|
||||
}
|
||||
if (url === undefined) {
|
||||
this.host = "";
|
||||
this.uri = "";
|
||||
this.query = {};
|
||||
} else {
|
||||
this.query = {};
|
||||
var host, path;
|
||||
var i = url.indexOf("://");
|
||||
if (i !== -1) {
|
||||
url = url.substr(i + 3);
|
||||
}
|
||||
var i = url.indexOf("?");
|
||||
if (i !== -1) {
|
||||
var query_str = url.substr(i + 1);
|
||||
url = url.substr(0, i);
|
||||
var spl = query_str.split("&");
|
||||
for (var i in spl) {
|
||||
var kv = spl[i];
|
||||
var index = kv.indexOf("=");
|
||||
var key, value;
|
||||
if (index >= 0) {
|
||||
key = kv.substr(0, index);
|
||||
value = kv.substr(index + 1);
|
||||
} else {
|
||||
key = kv;
|
||||
value = "";
|
||||
}
|
||||
if (key !== "") {
|
||||
key = decodeURI(key);
|
||||
value = decodeURI(value);
|
||||
if (this.query[key] === undefined) {
|
||||
this.query[key] = [value];
|
||||
} else {
|
||||
this.query[key].push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var i = url.indexOf("/");
|
||||
if (i === -1) {
|
||||
host = url;
|
||||
path = "/";
|
||||
} else {
|
||||
host = url.substr(0, i);
|
||||
path = url.substr(i);
|
||||
}
|
||||
this.host = host;
|
||||
this.uri = decodeURI(path);
|
||||
}
|
||||
if (headers === undefined) {
|
||||
this.headers = {};
|
||||
} else {
|
||||
this.headers = headers;
|
||||
}
|
||||
if (body === undefined) {
|
||||
this.body = "";
|
||||
} else {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
function findHeader(r, header) {
|
||||
for (var k in r.headers) {
|
||||
if (k.toLowerCase() === header.toLowerCase()) {
|
||||
return r.headers[k];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build a CanonicalRequest from a regular request string
|
||||
//
|
||||
// CanonicalRequest =
|
||||
// HTTPRequestMethod + '\n' +
|
||||
// CanonicalURI + '\n' +
|
||||
// CanonicalQueryString + '\n' +
|
||||
// CanonicalHeaders + '\n' +
|
||||
// SignedHeaders + '\n' +
|
||||
// HexEncode(Hash(RequestPayload))
|
||||
function CanonicalRequest(r, signedHeaders) {
|
||||
var hexencode = findHeader(r, HeaderContentSha256);
|
||||
if (hexencode === null) {
|
||||
var data = RequestPayload(r);
|
||||
hexencode = crypto_wrapper.HexEncodeSHA256Hash(data);
|
||||
}
|
||||
return (
|
||||
r.method +
|
||||
"\n" +
|
||||
CanonicalURI(r) +
|
||||
"\n" +
|
||||
CanonicalQueryString(r) +
|
||||
"\n" +
|
||||
CanonicalHeaders(r, signedHeaders) +
|
||||
"\n" +
|
||||
signedHeaders.join(";") +
|
||||
"\n" +
|
||||
hexencode
|
||||
);
|
||||
}
|
||||
|
||||
function CanonicalURI(r) {
|
||||
var pattens = r.uri.split("/");
|
||||
var uri = [];
|
||||
for (var k in pattens) {
|
||||
var v = pattens[k];
|
||||
uri.push(urlEncode(v));
|
||||
}
|
||||
var urlpath = uri.join("/");
|
||||
if (urlpath[urlpath.length - 1] !== "/") {
|
||||
urlpath = urlpath + "/";
|
||||
}
|
||||
//r.uri = urlpath
|
||||
return urlpath;
|
||||
}
|
||||
|
||||
function CanonicalQueryString(r) {
|
||||
var keys = [];
|
||||
for (var key in r.query) {
|
||||
keys.push(key);
|
||||
}
|
||||
keys.sort();
|
||||
var a = [];
|
||||
for (var i in keys) {
|
||||
var key = urlEncode(keys[i]);
|
||||
var value = r.query[keys[i]];
|
||||
if (Array.isArray(value)) {
|
||||
value.sort();
|
||||
for (var iv in value) {
|
||||
a.push(key + "=" + urlEncode(value[iv]));
|
||||
}
|
||||
} else {
|
||||
a.push(key + "=" + urlEncode(value));
|
||||
}
|
||||
}
|
||||
return a.join("&");
|
||||
}
|
||||
|
||||
function CanonicalHeaders(r, signedHeaders) {
|
||||
var headers = {};
|
||||
for (var key in r.headers) {
|
||||
headers[key.toLowerCase()] = r.headers[key];
|
||||
}
|
||||
var a = [];
|
||||
for (var i in signedHeaders) {
|
||||
var value = headers[signedHeaders[i]];
|
||||
a.push(signedHeaders[i] + ":" + value.trim());
|
||||
}
|
||||
return a.join("\n") + "\n";
|
||||
}
|
||||
|
||||
function SignedHeaders(r) {
|
||||
var a = [];
|
||||
for (var key in r.headers) {
|
||||
a.push(key.toLowerCase());
|
||||
}
|
||||
a.sort();
|
||||
return a;
|
||||
}
|
||||
|
||||
function RequestPayload(r) {
|
||||
return r.body;
|
||||
}
|
||||
|
||||
// Create a "String to Sign".
|
||||
function StringToSign(canonicalRequest, t) {
|
||||
var bytes = crypto_wrapper.HexEncodeSHA256Hash(canonicalRequest);
|
||||
return Algorithm + "\n" + t + "\n" + bytes;
|
||||
}
|
||||
|
||||
// Create the HWS Signature.
|
||||
function SignStringToSign(stringToSign, signingKey) {
|
||||
return crypto_wrapper.hmacsha256(signingKey, stringToSign);
|
||||
}
|
||||
|
||||
// Get the finalized value for the "Authorization" header. The signature
|
||||
// parameter is the output from SignStringToSign
|
||||
function AuthHeaderValue(signature, Key, signedHeaders) {
|
||||
return Algorithm + " Access=" + Key + ", SignedHeaders=" + signedHeaders.join(";") + ", Signature=" + signature;
|
||||
}
|
||||
|
||||
function twoChar(s) {
|
||||
if (s >= 10) {
|
||||
return "" + s;
|
||||
} else {
|
||||
return "0" + s;
|
||||
}
|
||||
}
|
||||
|
||||
function getTime() {
|
||||
var date = new Date();
|
||||
return (
|
||||
"" +
|
||||
date.getUTCFullYear() +
|
||||
twoChar(date.getUTCMonth() + 1) +
|
||||
twoChar(date.getUTCDate()) +
|
||||
"T" +
|
||||
twoChar(date.getUTCHours()) +
|
||||
twoChar(date.getUTCMinutes()) +
|
||||
twoChar(date.getUTCSeconds()) +
|
||||
"Z"
|
||||
);
|
||||
}
|
||||
|
||||
function Signer() {
|
||||
this.Key = "";
|
||||
this.Secret = "";
|
||||
}
|
||||
|
||||
Signer.prototype.Sign = function (r) {
|
||||
var headerTime = findHeader(r, HeaderXDate);
|
||||
if (headerTime === null) {
|
||||
headerTime = getTime();
|
||||
r.headers[HeaderXDate] = headerTime;
|
||||
}
|
||||
if (r.method !== "PUT" && r.method !== "PATCH" && r.method !== "POST") {
|
||||
r.body = "";
|
||||
}
|
||||
var queryString = CanonicalQueryString(r);
|
||||
if (queryString !== "") {
|
||||
queryString = "?" + queryString;
|
||||
}
|
||||
var options = {
|
||||
hostname: r.host,
|
||||
path: encodeURI(r.uri) + queryString,
|
||||
method: r.method,
|
||||
headers: r.headers,
|
||||
};
|
||||
if (findHeader(r, "host") === null) {
|
||||
r.headers.host = r.host;
|
||||
}
|
||||
var signedHeaders = SignedHeaders(r);
|
||||
var canonicalRequest = CanonicalRequest(r, signedHeaders);
|
||||
var stringToSign = StringToSign(canonicalRequest, headerTime);
|
||||
var signature = SignStringToSign(stringToSign, this.Secret);
|
||||
options.headers[HeaderAuthorization] = AuthHeaderValue(signature, this.Key, signedHeaders);
|
||||
return options;
|
||||
};
|
||||
return {
|
||||
HttpRequest: HttpRequest,
|
||||
Signer: Signer,
|
||||
urlEncode: urlEncode,
|
||||
findHeader: findHeader,
|
||||
SignedHeaders: SignedHeaders,
|
||||
CanonicalRequest: CanonicalRequest,
|
||||
StringToSign: StringToSign,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
var assert = require("assert");
|
||||
var signer = require('./signer')
|
||||
|
||||
var s = ""
|
||||
for (i = 0; i < 0x80; i++) {
|
||||
s = s + signer.urlEncode(String.fromCharCode(i))
|
||||
}
|
||||
console.log(s)
|
||||
assert.equal(s, "%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F")
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// @ts-ignore
|
||||
import signer from "./signer";
|
||||
import https from "https";
|
||||
import { HuaweiAccess } from "../access";
|
||||
import { axios } from "@certd/acme-client";
|
||||
|
||||
export type ApiRequestOptions = {
|
||||
method: string;
|
||||
url: string;
|
||||
headers: any;
|
||||
body: any;
|
||||
};
|
||||
export class HuaweiYunClient {
|
||||
access: HuaweiAccess;
|
||||
constructor(access: HuaweiAccess) {
|
||||
this.access = access;
|
||||
}
|
||||
async request(options: ApiRequestOptions) {
|
||||
const sig = new signer.Signer();
|
||||
//Set the AK/SK to sign and authenticate the request.
|
||||
sig.Key = this.access.accessKeyId;
|
||||
sig.Secret = this.access.accessKeySecret;
|
||||
|
||||
//The following example shows how to set the request URL and parameters to query a VPC list.
|
||||
//Specify a request method, such as GET, PUT, POST, DELETE, HEAD, and PATCH.
|
||||
//Set request host.
|
||||
//Set request URI.
|
||||
//Set parameters for the request URL.
|
||||
const r = new signer.HttpRequest(options.method, options.url, options.headers, options.body);
|
||||
//Add header parameters, for example, x-domain-id for invoking a global service and x-project-id for invoking a project-level service.
|
||||
r.headers = { "Content-Type": "application/json" };
|
||||
//Add a body if you have specified the PUT or POST method. Special characters, such as the double quotation mark ("), contained in the body must be escaped.
|
||||
r.body = "";
|
||||
|
||||
const opt = sig.Sign(r);
|
||||
console.log("opt", opt);
|
||||
console.log(opt.headers["X-Sdk-Date"]);
|
||||
console.log(opt.headers["Authorization"]);
|
||||
const res = await axios.request(opt);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
// HWS API Gateway Signature
|
||||
(function (root, factory) {
|
||||
"use strict";
|
||||
|
||||
/*global define*/
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD
|
||||
define(["CryptoJS"], function (CryptoJS) {
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return CryptoJS.HmacSHA256(message, keyByte).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return CryptoJS.SHA256(body);
|
||||
},
|
||||
};
|
||||
return factory(crypto_wrapper);
|
||||
});
|
||||
} else if (typeof wx === "object") {
|
||||
// wechat
|
||||
var CryptoJS = require("./js/hmac-sha256.js");
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return CryptoJS.HmacSHA256(message, keyByte).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return CryptoJS.SHA256(body);
|
||||
},
|
||||
};
|
||||
module.exports = factory(crypto_wrapper);
|
||||
} else if (typeof module === "object" && module.exports) {
|
||||
// Node
|
||||
var crypto = require("crypto");
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return crypto.createHmac("SHA256", keyByte).update(message).digest().toString("hex");
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return crypto.createHash("SHA256").update(body).digest().toString("hex");
|
||||
},
|
||||
};
|
||||
module.exports = factory(crypto_wrapper);
|
||||
} else {
|
||||
// Browser
|
||||
var CryptoJS = root.CryptoJS;
|
||||
var crypto_wrapper = {
|
||||
hmacsha256: function (keyByte, message) {
|
||||
return CryptoJS.HmacSHA256(message, keyByte).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
HexEncodeSHA256Hash: function (body) {
|
||||
return CryptoJS.SHA256(body);
|
||||
},
|
||||
};
|
||||
root.signer = factory(crypto_wrapper);
|
||||
}
|
||||
})(this, function (crypto_wrapper) {
|
||||
"use strict";
|
||||
|
||||
var Algorithm = "SDK-HMAC-SHA256";
|
||||
var HeaderXDate = "X-Sdk-Date";
|
||||
var HeaderAuthorization = "Authorization";
|
||||
var HeaderContentSha256 = "x-sdk-content-sha256";
|
||||
|
||||
const hexTable = new Array(256);
|
||||
for (var i = 0; i < 256; ++i) hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
|
||||
|
||||
const noEscape = [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // 0 - 15
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // 16 - 31
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0, // 32 - 47
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // 48 - 63
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1, // 64 - 79
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1, // 80 - 95
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1, // 96 - 111
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0, // 112 - 127
|
||||
];
|
||||
|
||||
// function urlEncode is based on https://github.com/nodejs/node/blob/master/lib/querystring.js
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
function urlEncode(str) {
|
||||
if (typeof str !== "string") {
|
||||
if (typeof str === "object") str = String(str);
|
||||
else str += "";
|
||||
}
|
||||
var out = "";
|
||||
var lastPos = 0;
|
||||
|
||||
for (var i = 0; i < str.length; ++i) {
|
||||
var c = str.charCodeAt(i);
|
||||
|
||||
// ASCII
|
||||
if (c < 0x80) {
|
||||
if (noEscape[c] === 1) continue;
|
||||
if (lastPos < i) out += str.slice(lastPos, i);
|
||||
lastPos = i + 1;
|
||||
out += hexTable[c];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastPos < i) out += str.slice(lastPos, i);
|
||||
|
||||
// Multi-byte characters ...
|
||||
if (c < 0x800) {
|
||||
lastPos = i + 1;
|
||||
out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
|
||||
continue;
|
||||
}
|
||||
if (c < 0xd800 || c >= 0xe000) {
|
||||
lastPos = i + 1;
|
||||
out += hexTable[0xe0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3f)] + hexTable[0x80 | (c & 0x3f)];
|
||||
continue;
|
||||
}
|
||||
// Surrogate pair
|
||||
++i;
|
||||
|
||||
if (i >= str.length) throw new errors.URIError("ERR_INVALID_URI");
|
||||
|
||||
var c2 = str.charCodeAt(i) & 0x3ff;
|
||||
|
||||
lastPos = i + 1;
|
||||
c = 0x10000 + (((c & 0x3ff) << 10) | c2);
|
||||
out += hexTable[0xf0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3f)] + hexTable[0x80 | ((c >> 6) & 0x3f)] + hexTable[0x80 | (c & 0x3f)];
|
||||
}
|
||||
if (lastPos === 0) return str;
|
||||
if (lastPos < str.length) return out + str.slice(lastPos);
|
||||
return out;
|
||||
}
|
||||
|
||||
function HttpRequest(method, url, headers, body) {
|
||||
if (method === undefined) {
|
||||
this.method = "";
|
||||
} else {
|
||||
this.method = method;
|
||||
}
|
||||
if (url === undefined) {
|
||||
this.host = "";
|
||||
this.uri = "";
|
||||
this.query = {};
|
||||
} else {
|
||||
this.query = {};
|
||||
var host, path;
|
||||
var i = url.indexOf("://");
|
||||
if (i !== -1) {
|
||||
url = url.substr(i + 3);
|
||||
}
|
||||
var i = url.indexOf("?");
|
||||
if (i !== -1) {
|
||||
var query_str = url.substr(i + 1);
|
||||
url = url.substr(0, i);
|
||||
var spl = query_str.split("&");
|
||||
for (var i in spl) {
|
||||
var kv = spl[i];
|
||||
var index = kv.indexOf("=");
|
||||
var key, value;
|
||||
if (index >= 0) {
|
||||
key = kv.substr(0, index);
|
||||
value = kv.substr(index + 1);
|
||||
} else {
|
||||
key = kv;
|
||||
value = "";
|
||||
}
|
||||
if (key !== "") {
|
||||
key = decodeURI(key);
|
||||
value = decodeURI(value);
|
||||
if (this.query[key] === undefined) {
|
||||
this.query[key] = [value];
|
||||
} else {
|
||||
this.query[key].push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var i = url.indexOf("/");
|
||||
if (i === -1) {
|
||||
host = url;
|
||||
path = "/";
|
||||
} else {
|
||||
host = url.substr(0, i);
|
||||
path = url.substr(i);
|
||||
}
|
||||
this.host = host;
|
||||
this.uri = decodeURI(path);
|
||||
}
|
||||
if (headers === undefined) {
|
||||
this.headers = {};
|
||||
} else {
|
||||
this.headers = headers;
|
||||
}
|
||||
if (body === undefined) {
|
||||
this.body = "";
|
||||
} else {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
function findHeader(r, header) {
|
||||
for (var k in r.headers) {
|
||||
if (k.toLowerCase() === header.toLowerCase()) {
|
||||
return r.headers[k];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build a CanonicalRequest from a regular request string
|
||||
//
|
||||
// CanonicalRequest =
|
||||
// HTTPRequestMethod + '\n' +
|
||||
// CanonicalURI + '\n' +
|
||||
// CanonicalQueryString + '\n' +
|
||||
// CanonicalHeaders + '\n' +
|
||||
// SignedHeaders + '\n' +
|
||||
// HexEncode(Hash(RequestPayload))
|
||||
function CanonicalRequest(r, signedHeaders) {
|
||||
var hexencode = findHeader(r, HeaderContentSha256);
|
||||
if (hexencode === null) {
|
||||
var data = RequestPayload(r);
|
||||
hexencode = crypto_wrapper.HexEncodeSHA256Hash(data);
|
||||
}
|
||||
return (
|
||||
r.method +
|
||||
"\n" +
|
||||
CanonicalURI(r) +
|
||||
"\n" +
|
||||
CanonicalQueryString(r) +
|
||||
"\n" +
|
||||
CanonicalHeaders(r, signedHeaders) +
|
||||
"\n" +
|
||||
signedHeaders.join(";") +
|
||||
"\n" +
|
||||
hexencode
|
||||
);
|
||||
}
|
||||
|
||||
function CanonicalURI(r) {
|
||||
var pattens = r.uri.split("/");
|
||||
var uri = [];
|
||||
for (var k in pattens) {
|
||||
var v = pattens[k];
|
||||
uri.push(urlEncode(v));
|
||||
}
|
||||
var urlpath = uri.join("/");
|
||||
if (urlpath[urlpath.length - 1] !== "/") {
|
||||
urlpath = urlpath + "/";
|
||||
}
|
||||
//r.uri = urlpath
|
||||
return urlpath;
|
||||
}
|
||||
|
||||
function CanonicalQueryString(r) {
|
||||
var keys = [];
|
||||
for (var key in r.query) {
|
||||
keys.push(key);
|
||||
}
|
||||
keys.sort();
|
||||
var a = [];
|
||||
for (var i in keys) {
|
||||
var key = urlEncode(keys[i]);
|
||||
var value = r.query[keys[i]];
|
||||
if (Array.isArray(value)) {
|
||||
value.sort();
|
||||
for (var iv in value) {
|
||||
a.push(key + "=" + urlEncode(value[iv]));
|
||||
}
|
||||
} else {
|
||||
a.push(key + "=" + urlEncode(value));
|
||||
}
|
||||
}
|
||||
return a.join("&");
|
||||
}
|
||||
|
||||
function CanonicalHeaders(r, signedHeaders) {
|
||||
var headers = {};
|
||||
for (var key in r.headers) {
|
||||
headers[key.toLowerCase()] = r.headers[key];
|
||||
}
|
||||
var a = [];
|
||||
for (var i in signedHeaders) {
|
||||
var value = headers[signedHeaders[i]];
|
||||
a.push(signedHeaders[i] + ":" + value.trim());
|
||||
}
|
||||
return a.join("\n") + "\n";
|
||||
}
|
||||
|
||||
function SignedHeaders(r) {
|
||||
var a = [];
|
||||
for (var key in r.headers) {
|
||||
a.push(key.toLowerCase());
|
||||
}
|
||||
a.sort();
|
||||
return a;
|
||||
}
|
||||
|
||||
function RequestPayload(r) {
|
||||
return r.body;
|
||||
}
|
||||
|
||||
// Create a "String to Sign".
|
||||
function StringToSign(canonicalRequest, t) {
|
||||
var bytes = crypto_wrapper.HexEncodeSHA256Hash(canonicalRequest);
|
||||
return Algorithm + "\n" + t + "\n" + bytes;
|
||||
}
|
||||
|
||||
// Create the HWS Signature.
|
||||
function SignStringToSign(stringToSign, signingKey) {
|
||||
return crypto_wrapper.hmacsha256(signingKey, stringToSign);
|
||||
}
|
||||
|
||||
// Get the finalized value for the "Authorization" header. The signature
|
||||
// parameter is the output from SignStringToSign
|
||||
function AuthHeaderValue(signature, Key, signedHeaders) {
|
||||
return Algorithm + " Access=" + Key + ", SignedHeaders=" + signedHeaders.join(";") + ", Signature=" + signature;
|
||||
}
|
||||
|
||||
function twoChar(s) {
|
||||
if (s >= 10) {
|
||||
return "" + s;
|
||||
} else {
|
||||
return "0" + s;
|
||||
}
|
||||
}
|
||||
|
||||
function getTime() {
|
||||
var date = new Date();
|
||||
return (
|
||||
"" +
|
||||
date.getUTCFullYear() +
|
||||
twoChar(date.getUTCMonth() + 1) +
|
||||
twoChar(date.getUTCDate()) +
|
||||
"T" +
|
||||
twoChar(date.getUTCHours()) +
|
||||
twoChar(date.getUTCMinutes()) +
|
||||
twoChar(date.getUTCSeconds()) +
|
||||
"Z"
|
||||
);
|
||||
}
|
||||
|
||||
function Signer() {
|
||||
this.Key = "";
|
||||
this.Secret = "";
|
||||
}
|
||||
|
||||
Signer.prototype.Sign = function (r) {
|
||||
var headerTime = findHeader(r, HeaderXDate);
|
||||
if (headerTime === null) {
|
||||
headerTime = getTime();
|
||||
r.headers[HeaderXDate] = headerTime;
|
||||
}
|
||||
if (r.method !== "PUT" && r.method !== "PATCH" && r.method !== "POST") {
|
||||
r.body = "";
|
||||
}
|
||||
var queryString = CanonicalQueryString(r);
|
||||
if (queryString !== "") {
|
||||
queryString = "?" + queryString;
|
||||
}
|
||||
var options = {
|
||||
hostname: r.host,
|
||||
path: encodeURI(r.uri) + queryString,
|
||||
method: r.method,
|
||||
headers: r.headers,
|
||||
};
|
||||
if (findHeader(r, "host") === null) {
|
||||
r.headers.host = r.host;
|
||||
}
|
||||
var signedHeaders = SignedHeaders(r);
|
||||
var canonicalRequest = CanonicalRequest(r, signedHeaders);
|
||||
var stringToSign = StringToSign(canonicalRequest, headerTime);
|
||||
var signature = SignStringToSign(stringToSign, this.Secret);
|
||||
options.headers[HeaderAuthorization] = AuthHeaderValue(signature, this.Key, signedHeaders);
|
||||
return options;
|
||||
};
|
||||
return {
|
||||
HttpRequest: HttpRequest,
|
||||
Signer: Signer,
|
||||
urlEncode: urlEncode,
|
||||
findHeader: findHeader,
|
||||
SignedHeaders: SignedHeaders,
|
||||
CanonicalRequest: CanonicalRequest,
|
||||
StringToSign: StringToSign,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export const ZoneOptions = [{ value: "cn-hangzhou" }];
|
||||
export function appendTimeSuffix(name: string) {
|
||||
if (name == null) {
|
||||
name = "certd";
|
||||
}
|
||||
return name + "-" + dayjs().format("YYYYMMDD-HHmmss");
|
||||
}
|
||||
|
||||
export function checkRet(ret: any) {
|
||||
if (ret.code != null) {
|
||||
throw new Error("执行失败:" + ret.Message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user