[hebe/insomnia] Refactor, extract signer from insomnia plugin
This commit is contained in:
parent
7fb3debe91
commit
25cbf7cf60
3 changed files with 116 additions and 108 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -62,3 +62,4 @@ typings/
|
|||
.idea/
|
||||
|
||||
vendor
|
||||
package-lock.json
|
||||
|
|
|
@ -1,120 +1,64 @@
|
|||
const uuid = require('uuid/v4');
|
||||
const {getSignatureValues} = require("./signer");
|
||||
|
||||
|
||||
aCrypto = require('crypto');
|
||||
const uuidv4 = require('uuid/v4');
|
||||
function getOrThrow(context, name) {
|
||||
let header = context.request.getHeader(name);
|
||||
if (header === null || header.length === 0) {
|
||||
throw `No ${name} header`;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
module.exports.requestHooks = [
|
||||
async (context) => {
|
||||
if (context.request.hasHeader('PrivateKey')) {
|
||||
let body = context.request.getBodyText();
|
||||
if (!context.request.hasHeader('PrivateKey')) return;
|
||||
|
||||
const pkey = "-----BEGIN PRIVATE KEY-----\n" + getOrThrow(context, "PrivateKey") + "\n-----END PRIVATE KEY-----";
|
||||
const fingerprint = getOrThrow(context, "Fingerprint");
|
||||
const deviceModel = getOrThrow(context, "DeviceModel");
|
||||
const firebaseToken = getOrThrow(context, "FirebaseToken");
|
||||
|
||||
let pkey = context.request.getHeader('PrivateKey');
|
||||
if (pkey === null) {
|
||||
throw 'No PrivateKey header';
|
||||
}
|
||||
pkey = "-----BEGIN PRIVATE KEY-----\n"+context.request.getHeader('PrivateKey')+"\n-----END PRIVATE KEY-----";
|
||||
let fingerprint = context.request.getHeader('Fingerprint');
|
||||
if (fingerprint === null || fingerprint.length === 0) {
|
||||
throw 'No Fingerprint header';
|
||||
}
|
||||
let deviceModel = context.request.getHeader('DeviceModel');
|
||||
if (deviceModel === null || fingerprint.length === 0) {
|
||||
throw 'No DeviceModel header';
|
||||
}
|
||||
let firebaseToken = context.request.getHeader('FirebaseToken');
|
||||
if (firebaseToken === null || firebaseToken.length === 0) {
|
||||
throw 'No FirebaseToken header';
|
||||
}
|
||||
let timestamp = +context.request.getHeader('Timestamp');
|
||||
if (timestamp === 0) timestamp = +new Date();
|
||||
const timestampStrHeader = new Date(timestamp + 1000).toUTCString();
|
||||
|
||||
let timestamp = + context.request.getHeader('Timestamp');
|
||||
if (timestamp === 0)
|
||||
timestamp = + new Date();
|
||||
const body = getWrappedBody(context.request.getMethod(), context.request.getBodyText(), fingerprint, firebaseToken, timestamp);
|
||||
context.request.setBodyText(body);
|
||||
|
||||
let timestampStr = new Date(timestamp + 3600*1000 + 1000).toUTCString();
|
||||
let timestampStrHeader = new Date(timestamp + 1000).toUTCString();
|
||||
const {digest, signature, headers, keyId, canonicalUrl} = getSignatureValues(fingerprint, pkey, body, context.request.getUrl(), timestamp);
|
||||
|
||||
context.request.setHeader('User-Agent', 'okhttp/3.11.0');
|
||||
context.request.setHeader('vOS', 'Android');
|
||||
context.request.setHeader('vDeviceModel', deviceModel);
|
||||
context.request.setHeader('vAPI', 1);
|
||||
context.request.setHeader('vDate', timestampStrHeader);
|
||||
context.request.setHeader('vCanonicalUrl', canonicalUrl);
|
||||
context.request.setHeader('Signature', `keyId="${keyId}",headers="${headers}",algorithm="sha256withrsa",signature=Base64(SHA256withRSA(${signature}))`);
|
||||
if (body != null) context.request.setHeader('Digest', `SHA-256=${digest}`);
|
||||
|
||||
|
||||
if (context.request.getMethod() !== 'POST') {
|
||||
if (context.request.getMethod() !== 'GET') {
|
||||
throw 'Incorrect request method (GET or POST).';
|
||||
}
|
||||
body = null
|
||||
}
|
||||
else {
|
||||
console.log(body);
|
||||
body = JSON.parse(body);
|
||||
console.log(body);
|
||||
body = JSON.stringify({
|
||||
AppName: 'DzienniczekPlus 2.0',
|
||||
AppVersion: '1.0',
|
||||
CertificateId: fingerprint,
|
||||
Envelope: body,
|
||||
FirebaseToken: firebaseToken,
|
||||
API: 1,
|
||||
RequestId: uuidv4(),
|
||||
Timestamp: timestamp,
|
||||
TimestampFormatted: timestampStr
|
||||
});
|
||||
context.request.setBodyText(body);
|
||||
console.log(body);
|
||||
}
|
||||
|
||||
let url = context.request.getUrl().match("(api/mobile/.+)");
|
||||
if (url == null) {
|
||||
throw 'The URL does not seem correct (does not match `(api/mobile/.+)` regex).';
|
||||
}
|
||||
url = encodeURIComponent(url[0]).toLowerCase();
|
||||
|
||||
let digest = "";
|
||||
if (body != null) {
|
||||
let hash = aCrypto.createHash('SHA256');
|
||||
hash.update(body);
|
||||
digest = hash.digest("base64");
|
||||
}
|
||||
|
||||
let signData = [
|
||||
['vCanonicalUrl', url],
|
||||
body == null ? null : ['Digest', digest],
|
||||
['vDate', timestampStrHeader]
|
||||
];
|
||||
|
||||
let headers = "";
|
||||
let values = "";
|
||||
let first = true;
|
||||
for (let data in signData) {
|
||||
data = signData[data];
|
||||
if (data == null)
|
||||
continue;
|
||||
if (!first)
|
||||
headers += " ";
|
||||
first = false;
|
||||
headers += data[0];
|
||||
values += data[1];
|
||||
}
|
||||
|
||||
console.log(headers);
|
||||
console.log(values);
|
||||
|
||||
let sign = aCrypto.createSign('RSA-SHA256');
|
||||
sign.update(values);
|
||||
let signature = sign.sign(pkey, "base64");
|
||||
|
||||
context.request.removeHeader('PrivateKey');
|
||||
context.request.removeHeader('Fingerprint');
|
||||
context.request.removeHeader('DeviceModel');
|
||||
context.request.removeHeader('Timestamp');
|
||||
context.request.removeHeader('FirebaseToken');
|
||||
context.request.setHeader('User-Agent', 'okhttp/3.11.0');
|
||||
context.request.setHeader('vOS', 'Android');
|
||||
context.request.setHeader('vDeviceModel', deviceModel);
|
||||
context.request.setHeader('vAPI', 1);
|
||||
context.request.setHeader('vDate', timestampStrHeader);
|
||||
context.request.setHeader('vCanonicalUrl', url);
|
||||
if (body != null)
|
||||
context.request.setHeader('Digest', 'SHA-256='+digest);
|
||||
context.request.setHeader('Signature', 'keyId="'+fingerprint+'",headers="'+headers+'",algorithm="sha256withrsa",signature=Base64(SHA256withRSA('+signature+'))');
|
||||
}
|
||||
context.request.removeHeader('PrivateKey');
|
||||
context.request.removeHeader('Fingerprint');
|
||||
context.request.removeHeader('DeviceModel');
|
||||
context.request.removeHeader('Timestamp');
|
||||
context.request.removeHeader('FirebaseToken');
|
||||
}
|
||||
];
|
||||
|
||||
function getWrappedBody(method, body, fingerprint, firebaseToken, timestamp) {
|
||||
if (method !== 'POST') {
|
||||
if (method !== 'GET') throw 'Incorrect request method (GET or POST).';
|
||||
else return null
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
AppName: 'DzienniczekPlus 2.0',
|
||||
AppVersion: '1.0',
|
||||
CertificateId: fingerprint,
|
||||
Envelope: JSON.parse(body),
|
||||
FirebaseToken: firebaseToken,
|
||||
API: 1,
|
||||
RequestId: uuid(),
|
||||
Timestamp: timestamp,
|
||||
TimestampFormatted: new Date(timestamp + 3600 * 1000 + 1000).toUTCString()
|
||||
});
|
||||
}
|
||||
|
|
63
hebe-insomnia-plugin/signer.js
Normal file
63
hebe-insomnia-plugin/signer.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
const aCrypto = require('crypto');
|
||||
|
||||
function getDigest(body) {
|
||||
if (body == null) return "";
|
||||
|
||||
const hash = aCrypto.createHash('SHA256');
|
||||
hash.update(body);
|
||||
return hash.digest("base64");
|
||||
}
|
||||
|
||||
function getSignature(values, pkey) {
|
||||
const sign = aCrypto.createSign('RSA-SHA256');
|
||||
sign.update(values);
|
||||
return sign.sign(pkey, "base64");
|
||||
}
|
||||
|
||||
function getCanonicalUrl(fullUrl) {
|
||||
const url = fullUrl.match("(api/mobile/.+)");
|
||||
if (url == null) throw 'The URL does not seem correct (does not match `(api/mobile/.+)` regex)';
|
||||
|
||||
return encodeURIComponent(url[0]).toLowerCase();
|
||||
}
|
||||
|
||||
function getHeadersList(body, digest, canonicalUrl, timestamp) {
|
||||
const timestampStrHeader = new Date(timestamp + 1000).toUTCString();
|
||||
let signData = [
|
||||
['vCanonicalUrl', canonicalUrl],
|
||||
body == null ? null : ['Digest', digest],
|
||||
['vDate', timestampStrHeader]
|
||||
];
|
||||
let headers = "";
|
||||
let values = "";
|
||||
let first = true;
|
||||
for (let data in signData) {
|
||||
data = signData[data];
|
||||
if (data == null)
|
||||
continue;
|
||||
if (!first)
|
||||
headers += " ";
|
||||
first = false;
|
||||
headers += data[0];
|
||||
values += data[1];
|
||||
}
|
||||
|
||||
return {"headers": headers, "values": values};
|
||||
}
|
||||
|
||||
function getSignatureValues(fingerprint, pkey, body, fullUrl, timestamp) {
|
||||
const canonicalUrl = getCanonicalUrl(fullUrl);
|
||||
const digest = getDigest(body);
|
||||
const {headers, values} = getHeadersList(body, digest, canonicalUrl, timestamp);
|
||||
const signature = getSignature(values, pkey);
|
||||
|
||||
return {
|
||||
"digest": digest,
|
||||
"keyId": fingerprint,
|
||||
"headers": headers,
|
||||
"signature": signature,
|
||||
"canonicalUrl": canonicalUrl
|
||||
};
|
||||
}
|
||||
|
||||
exports.getSignatureValues = getSignatureValues;
|
Loading…
Reference in a new issue