diff --git a/.eslintrc b/.eslintrc
index cc0f4cd..155751f 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -32,6 +32,8 @@
"@typescript-eslint/no-var-requires": 0,
"no-console": 0,
"import/no-unresolved": 0,
+ "require-atomic-updates": 0,
+ "@shopify/prefer-early-return": 0,
" import/no-unresolved": 0
}
}
diff --git a/index.ts b/index.ts
index 934ce84..d5b008d 100644
--- a/index.ts
+++ b/index.ts
@@ -1,9 +1,10 @@
import yargs from 'yargs';
import {hideBin} from 'yargs/helpers';
-import {startSession} from "./src/startSession";
+import {login, logout, startSession} from "./src/startSession";
import {
- deleteMessage, getInBoxSMS,
+ deleteMessage,
getContactSMSPages,
+ getInBoxSMS,
getSMSByUsers,
getSMSContacts,
getSMSPages,
@@ -14,29 +15,52 @@ import {controlMobileData, reconnect, status} from "./src/MobileData";
// @ts-ignore
yargs(hideBin(process.argv))
.command('sendSMS', 'send SMS to contact or group of contacts', (yargs) => {
+ // @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('phone', {
describe: 'phones with ; as separator ',
- type:"string",
+ type: "string",
}).positional('message', {
describe: 'text message ',
- type:"string",
+ type: "string",
})
}, async (argv) => {
- const sessionData = await startSession(argv.url);
- if (!argv.phone) {
- throw new Error('Phone number is not defined');
- return;
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ if (!argv.phone) {
+ throw new Error('Phone number is not defined');
+ return;
+ }
+ await sendMessage(sessionData, argv.phone, argv.message || '');
+ } finally {
+ await logout(argv.url);
}
- await sendMessage(sessionData, argv.phone, argv.message||'');
}).command('contacts', 'get contact list with the latest sms messages', (yargs) => {
- return yargs
+ // @ts-ignore
+ return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('page', {
describe: 'sms page',
default: 1
@@ -48,22 +72,28 @@ yargs(hideBin(process.argv))
default: 'none'
})
}, async (argv) => {
- const sessionData = await startSession(argv.url);
- switch (argv.exportFormat) {
- case 'json': {
- break;
- }
- case 'xml': {
- break;
- }
- case 'none': {
- break;
- }
- default: {
- throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ switch (argv.exportFormat) {
+ case 'json': {
+ break;
+ }
+ case 'xml': {
+ break;
+ }
+ case 'none': {
+ break;
+ }
+ default: {
+ throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ }
}
+
+ await getSMSContacts(sessionData, argv.page, argv.exportFile, argv.exportFormat);
+ } finally {
+ await logout(argv.url);
}
- await getSMSContacts(sessionData, argv.page, argv.exportFile, argv.exportFormat);
}).command('messages', 'get all messages from InBox', (yargs) => {
return yargs
.positional('url', {
@@ -72,7 +102,16 @@ yargs(hideBin(process.argv))
}).positional('deleteAfter', {
describe: 'delete all messages after reading ',
default: false
- }).positional('exportFile', {
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
+ })
+ .positional('exportFile', {
describe: 'export to file',
default: './inbox.list'
}).positional('exportFormat', {
@@ -80,24 +119,38 @@ yargs(hideBin(process.argv))
default: 'none'
})
}, async (argv) => {
- const sessionData = await startSession(argv.url);
- switch (argv.exportFormat) {
- case 'json': {
- break;
- }
- case 'none': {
- break;
- }
- default: {
- throw new Error(`export Format ${argv.exportFile} does not supported: supported only: json,none`)
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ switch (argv.exportFormat) {
+ case 'json': {
+ break;
+ }
+ case 'none': {
+ break;
+ }
+ default: {
+ throw new Error(`export Format ${argv.exportFile} does not supported: supported only: json,none`)
+ }
}
+ await getInBoxSMS(sessionData, argv.deleteAfter, argv.exportFile, argv.exportFormat);
+ } finally {
+ await logout(argv.url);
}
- await getInBoxSMS(sessionData, argv.deleteAfter, argv.exportFile, argv.exportFormat);
}).command('contactPages', 'contact list pages', (yargs) => {
+ // @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('exportFile', {
describe: 'export to file',
default: './contactsCount.list'
@@ -106,23 +159,30 @@ yargs(hideBin(process.argv))
default: 'none'
})
}, async (argv) => {
- const sessionData = await startSession(argv.url);
- switch (argv.exportFormat) {
- case 'json': {
- break;
- }
- case 'xml': {
- break;
- }
- case 'none': {
- break;
- }
- default: {
- throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+
+ switch (argv.exportFormat) {
+ case 'json': {
+ break;
+ }
+ case 'xml': {
+ break;
+ }
+ case 'none': {
+ break;
+ }
+ default: {
+ throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ }
}
+ await getSMSPages(sessionData, argv.exportFile, argv.exportFormat);
+ } finally {
+ await logout(argv.url);
}
- await getSMSPages(sessionData, argv.exportFile, argv.exportFormat);
}).command('sms', 'get contact SMS list', (yargs) => {
+ // @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
@@ -130,6 +190,14 @@ yargs(hideBin(process.argv))
}).positional('phone', {
describe: 'contact phone number',
type: 'string'
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('page', {
describe: 'sms page',
default: 1
@@ -144,30 +212,44 @@ yargs(hideBin(process.argv))
default: false
})
}, async (argv) => {
- const sessionData = await startSession(argv.url);
- if (!argv.phone) {
- throw new Error('phone is not defined');
- }
- switch (argv.exportFormat) {
- case 'json': {
- break;
- }
- case 'xml': {
- break;
- }
- case 'none': {
- break;
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ if (!argv.phone) {
+ throw new Error('phone is not defined');
}
- default: {
- throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ switch (argv.exportFormat) {
+ case 'json': {
+ break;
+ }
+ case 'xml': {
+ break;
+ }
+ case 'none': {
+ break;
+ }
+ default: {
+ throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ }
}
+ await getSMSByUsers(sessionData, argv.phone, argv.page, argv.exportFile, argv.exportFormat, argv.deleteAfter);
+ } finally {
+ await logout(argv.url);
}
- await getSMSByUsers(sessionData, argv.phone, argv.page, argv.exportFile, argv.exportFormat, argv.deleteAfter);
}).command('pages', 'count of sms pages', (yargs) => {
+// @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('phone', {
describe: 'contact phone number',
type: 'string'
@@ -179,72 +261,111 @@ yargs(hideBin(process.argv))
default: 'none'
})
}, async (argv) => {
- const sessionData = await startSession(argv.url);
- if (!argv.phone) {
- throw new Error('phone is not defined');
- }
- switch (argv.exportFormat) {
- case 'json': {
- break;
- }
- case 'xml': {
- break;
- }
- case 'none': {
- break;
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ if (!argv.phone) {
+ throw new Error('phone is not defined');
}
- default: {
- throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ switch (argv.exportFormat) {
+ case 'json': {
+ break;
+ }
+ case 'xml': {
+ break;
+ }
+ case 'none': {
+ break;
+ }
+ default: {
+ throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ }
}
+ await getContactSMSPages(sessionData, argv.phone, argv.exportFile, argv.exportFormat);
+ } finally {
+ await logout(argv.url);
}
- await getContactSMSPages(sessionData, argv.phone, argv.exportFile, argv.exportFormat);
-}).command('deleteSMS', 'delete sms by smsId', (yargs) => {
+}).command('deleteSMS', 'delete sms by smsId', (yargs: any) => {
+ // @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ })
+ .positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('messageId', {
describe: 'messageId or index',
type: 'string'
})
-}, async (argv) => {
- const sessionData = await startSession(argv.url);
- if (!argv.messageId) {
- throw new Error('messageId is not defined');
+}, async (argv: any) => {
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ if (!argv.messageId) {
+ throw new Error('messageId is not defined');
+ }
+ await deleteMessage(sessionData, argv.messageId);
+ } finally {
+ await logout(argv.url)
}
- await deleteMessage(sessionData, argv.messageId);
-}).command('mobileData', 'Enable/Disable or Reconnect Mobile Data', (yargs:any) => {
+}).command('mobileData', 'Enable/Disable or Reconnect Mobile Data', (yargs: any) => {
+ // @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ }).positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('mode', {
describe: 'change mobile data to on,off or reconnect',
})
-}, async (argv:any) => {
- const sessionData = await startSession(argv.url);
- switch (argv.mode) {
- case 'reconnect': {
- await reconnect(sessionData);
- return;
- }
- case 'on': {
- break;
- }
- case 'off': {
- break
- }
- default: {
- throw new Error('Does not support Mode: ' + argv.mode + '. Supported only on,off,reconnect')
+}, async (argv: any) => {
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ switch (argv.mode) {
+ case 'reconnect': {
+ await reconnect(sessionData);
+ return;
+ }
+ case 'on': {
+ break;
+ }
+ case 'off': {
+ break
+ }
+ default: {
+ throw new Error('Does not support Mode: ' + argv.mode + '. Supported only on,off,reconnect')
+ }
}
+ await controlMobileData(sessionData, argv.mode);
+ } finally {
+ await logout(argv.url);
}
- await controlMobileData(sessionData, argv.mode);
-}).command('monitoring', 'current Monitoring status', (yargs:any) => {
+}).command('monitoring', 'current Monitoring status', (yargs: any) => {
// @ts-ignore
return yargs
.positional('url', {
describe: 'huawei host',
default: '192.168.8.1'
+ }).positional('username', {
+ describe: 'huawei username',
+ default: 'admin'
+ })
+ .positional('password', {
+ describe: 'huawei password',
+ type: 'string'
}).positional('exportFile', {
describe: 'export to file',
default: './monitoring.log'
@@ -252,23 +373,28 @@ yargs(hideBin(process.argv))
describe: 'export format (xml, json, none)',
default: 'none'
})
-}, async (argv:any) => {
- const sessionData = await startSession(argv.url);
- switch (argv.exportFormat) {
- case 'json': {
- break;
- }
- case 'xml': {
- break;
- }
- case 'none': {
- break;
- }
- default: {
- throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+}, async (argv: any) => {
+ await login(argv.url, argv.username, argv.password);
+ try {
+ const sessionData = await startSession(argv.url);
+ switch (argv.exportFormat) {
+ case 'json': {
+ break;
+ }
+ case 'xml': {
+ break;
+ }
+ case 'none': {
+ break;
+ }
+ default: {
+ throw new Error(`export Format ${argv.exportFile} does not supported: supported only: xml,json,none`)
+ }
}
+ await status(sessionData, argv.exportFile, argv.exportFormat);
+ } finally {
+ await logout(argv.url);
}
- await status(sessionData, argv.exportFile, argv.exportFormat);
})
// .option('verbose', {
// alias: 'v',
diff --git a/jslib/public.js b/jslib/public.js
index a8ae124..daa8773 100644
--- a/jslib/public.js
+++ b/jslib/public.js
@@ -4,7 +4,15 @@ const {restCalls} = require("../src/utils/DefaultRestCalls");
const parser = require('xml2js');
const CryptoJS = require('crypto-js');
const {RSAKey} = require('./rsa');
-
+const publicKey = {
+ publicKey:null,
+};
+const publicSession = {
+ login:'0',
+ session:'',
+ token1:'',
+ token2:''
+};
var C = CryptoJS;
var C_lib = C.lib;
@@ -103,12 +111,15 @@ C.SCRAM = function (cfg) {
async function getPublicKey(session){
- const resp = await restCalls.fetchData(`http://${session.url}/api/webserver/publickey`,'GET', {
- 'cookie': `sessionId=${session.SesInfo}`,
- __RequestVerificationToken: session.TokInfo
- });
- const message = await parser.parseStringPromise(resp);
- return message.response;
+ if (!publicKey.publicKey){
+ const resp = await restCalls.fetchData(`http://${session.url}/api/webserver/publickey`,'GET', {
+ 'cookie': `sessionId=${session.SesInfo}`,
+ __RequestVerificationToken: session.TokInfo
+ });
+ const message = await parser.parseStringPromise(resp);
+ publicKey.publicKey= message.response;
+ }
+ return publicKey.publicKey
}
function utf8Encode(string) {
@@ -293,3 +304,5 @@ function dataDecrypt(scram,smsNonce,smsSalt,nonceStr,encryptedData) {
module.exports.dataDecrypt = dataDecrypt;
module.exports.CryptoJS = CryptoJS;
module.exports.doRSAEncrypt = doRSAEncrypt;
+module.exports.publicKey = publicKey;
+module.exports.publicSession = publicSession;
diff --git a/package.json b/package.json
index e3db6e7..6ddab80 100644
--- a/package.json
+++ b/package.json
@@ -1,18 +1,18 @@
{
"name": "e3372h-320-cli",
- "version": "1.0.5",
+ "version": "1.1.1",
"description": "e3372h-320 client",
"main": "index.js",
"scripts": {
- "sendSMS": "node index.js sendSMS --phone=+11111111111 --message=test123 --url=192.168.89.1 ",
- "contacts": "node index.js contacts --url=192.168.89.1",
- "getContactsCount": "node index.js contactPages --url=192.168.89.1 --exportFormat=json",
- "sms": "node index.js sms --phone=+11111111111 --url=192.168.89.1 --page=1",
- "pages": "node index.js pages --phone=+11111111111 --url=192.168.89.1 --exportFormat=json",
- "enableData": "node index.js mobileData --mode=on --url=192.168.89.1",
- "disableData": "node index.js mobileData --mode=off --url=192.168.89.1",
- "reconnected": "node index.js mobileData --mode=reconnect --url=192.168.89.1",
- "monitoring": "node index.js monitoring --url=192.168.89.1",
+ "sendSMS": "node index.js sendSMS --phone=+11111111111 --message=test123 --url=192.168.89.1 --password=testPassword ",
+ "contacts": "node index.js contacts --url=192.168.89.1 --password=testPassword",
+ "getContactsCount": "node index.js contactPages --url=192.168.89.1 --exportFormat=json --password=testPassword",
+ "sms": "node index.js sms --phone=+380674819807 --url=192.168.89.1 --page=1 --password=testPassword",
+ "pages": "node index.js pages --phone=+11111111111 --url=192.168.89.1 --exportFormat=json --password=testPassword",
+ "enableData": "node index.js mobileData --mode=on --url=192.168.89.1 --password=testPassword",
+ "disableData": "node index.js mobileData --mode=off --url=192.168.89.1 --password=testPassword",
+ "reconnected": "node index.js mobileData --mode=reconnect --url=192.168.89.1 --password=testPassword",
+ "monitoring": "node index.js monitoring --url=192.168.89.1 --password=testPassword",
"lint": "eslint src --ext .ts src",
"build": "tsc --build",
"lint:fix": "eslint --fix src --ext .ts"
diff --git a/src/ListSMS.ts b/src/ListSMS.ts
index 801087d..b7917d7 100644
--- a/src/ListSMS.ts
+++ b/src/ListSMS.ts
@@ -5,6 +5,7 @@ import parser from 'xml2js';
import {SessionData, startSession} from './startSession';
import {restCalls} from "./utils/DefaultRestCalls";
import {ExportFormat} from "./utils/Constants";
+import {getSessionHeaders} from "./utils/HuaweiUtils";
const huawei = require('../jslib/public');
@@ -45,12 +46,9 @@ export async function getSMSByUsers(sessionData: SessionData,
const nonceStr = smsNonce + smsSalt;
const encrpt = await huawei.doRSAEncrypt(sessionData0, nonceStr);
const data = await huawei.doRSAEncrypt(sessionData, `${phone}${pageindex}20${encrpt}`);
- const resp = await restCalls.sendData(`http://${sessionData0.url}/api/sms/sms-list-phone`, 'POST', data, {
- __RequestVerificationToken: sessionData0.TokInfo,
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8;enc',
- Cookie: `SessionId=${sessionData0.SesInfo}`,
- });
- const pwdret = await parser.parseStringPromise((resp));
+ const resp = await restCalls.sendDataRaw(`http://${sessionData0.url}/api/sms/sms-list-phone`, 'POST', data, await getSessionHeaders(sessionData.url));
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const pwdret = await parser.parseStringPromise((resp.data));
const ret = huawei.dataDecrypt(scram, smsNonce, smsSalt, nonceStr, pwdret);
if (deleteAfter) {
const json = await parser.parseStringPromise(ret);
@@ -81,20 +79,16 @@ export async function getContactSMSPages(sessionData: SessionData,
exportFile: string,
exportFormat: ExportFormat) {
const data = await huawei.doRSAEncrypt(sessionData, `${phone}`);
- const resp = await restCalls.sendData(`http://${sessionData.url}/api/sms/sms-count-contact`, 'POST', data, {
- __RequestVerificationToken: sessionData.TokInfo,
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8;enc',
- Cookie: `SessionId=${sessionData.SesInfo}`,
- });
-
- const json = await parser.parseStringPromise(resp);
+ const resp = await restCalls.sendDataRaw(`http://${sessionData.url}/api/sms/sms-count-contact`, 'POST', data, await getSessionHeaders(sessionData.url));
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const json = await parser.parseStringPromise(resp.data);
let number = Math.floor(json.response.count / 21);
if (number > 0) {
number += 1;
}
if (exportFormat !== 'hide') {
if (exportFormat === 'xml') {
- await saveFile(exportFile, resp);
+ await saveFile(exportFile, resp.data);
console.info(`xml file ${exportFile} created`);
} else if (exportFormat === 'json') {
await saveFile(exportFile, JSON.stringify(await parser.parseStringPromise(resp)));
@@ -114,7 +108,7 @@ export async function getSMSPages(sessionData: SessionData,
Cookie: `SessionId=${sessionData.SesInfo}`,
});
const json = await parser.parseStringPromise(resp);
- const number = Math.floor((json.response.LocalInbox[0] + json.response.LocalOutbox[0]) / 21);
+ const number = Math.floor((json.response.LocalInbox[0] + json.response.LocalOutbox[0]) / 21) + 1;
if (exportFormat !== 'hide') {
if (exportFormat === 'xml') {
await saveFile(exportFile, resp);
@@ -153,12 +147,9 @@ export async function sendMessage(sessionData: SessionData,
const nonceStr = smsNonce + smsSalt;
const encrpt = await huawei.doRSAEncrypt(sessionData, nonceStr);
const data = await huawei.doRSAEncrypt(sessionData, `-1${(phones)}${message}${message.length}12021-10-27 00:12:24${encrpt}`);
- const resp = await restCalls.sendData(`http://${sessionData.url}/api/sms/send-sms`, 'POST', data, {
- __RequestVerificationToken: sessionData.TokInfo,
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8;enc',
- Cookie: `SessionId=${sessionData.SesInfo}`,
- });
- const json = await parser.parseStringPromise(resp);
+ const resp = await restCalls.sendDataRaw(`http://${sessionData.url}/api/sms/send-sms`, 'POST', data, await getSessionHeaders(sessionData.url));
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const json = await parser.parseStringPromise(resp.data);
if (json.response !== 'OK') {
throw new Error(`Delete message error: ${JSON.stringify(json)}`);
}
@@ -215,13 +206,10 @@ export async function getSMSContacts(sessionData0: SessionData,
const nonceStr = smsNonce + smsSalt;
const encrpt = await huawei.doRSAEncrypt(sessionData, nonceStr);
const data = await huawei.doRSAEncrypt(sessionData, `${pageindex}20${encrpt}`);
- const resp = await restCalls.sendData(`http://${sessionData.url}/api/sms/sms-list-contact`, 'POST',
- data, {
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8;enc',
- __RequestVerificationToken: sessionData.TokInfo,
- Cookie: `SessionId=${sessionData.SesInfo}`,
- });
- const pwdret = await parser.parseStringPromise(resp);
+ const resp = await restCalls.sendDataRaw(`http://${sessionData.url}/api/sms/sms-list-contact`, 'POST',
+ data, await getSessionHeaders(sessionData.url));
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const pwdret = await parser.parseStringPromise(resp.data);
const ret = huawei.dataDecrypt(scram, smsNonce, smsSalt, nonceStr, pwdret);
const json = await parser.parseStringPromise(ret);
if (exportFormat !== 'hide') {
diff --git a/src/MobileData.ts b/src/MobileData.ts
index 8582d22..f13b551 100644
--- a/src/MobileData.ts
+++ b/src/MobileData.ts
@@ -5,7 +5,9 @@ import parser from "xml2js";
import {SessionData} from "./startSession";
import {restCalls} from "./utils/DefaultRestCalls";
import {ExportFormat} from "./utils/Constants";
+import {getSessionHeaders} from "./utils/HuaweiUtils";
+const huawei = require('../jslib/public');
type MobileStatus = 'on' | 'off';
@@ -14,12 +16,10 @@ async function saveFile(filename: string, data: string) {
}
export async function controlMobileData(sessionData: SessionData, mobileStatus: MobileStatus) {
- const data = `${mobileStatus === 'on' ? 1 : 0}`;
- const resp = await restCalls.sendData(`http://${sessionData.url}/api/dialup/mobile-dataswitch`, 'POST', data, {
- __RequestVerificationToken: sessionData.TokInfo,
- Cookie: `SessionId=${sessionData.SesInfo}`,
- });
- const json = await parser.parseStringPromise(resp);
+ const data = await huawei.doRSAEncrypt(sessionData, `${mobileStatus === 'on' ? 1 : 0}`);
+ const resp = await restCalls.sendDataRaw(`http://${sessionData.url}/api/dialup/mobile-dataswitch`, 'POST', data, await getSessionHeaders(sessionData.url));
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const json = await parser.parseStringPromise(resp.data);
if (json.response !== 'OK') {
throw new Error(`Control Mobile Data error: ${JSON.stringify(json)}`);
}
@@ -27,12 +27,10 @@ export async function controlMobileData(sessionData: SessionData, mobileStatus:
}
export async function reconnect(sessionData: SessionData) {
- const data = `1`;
- const resp = await restCalls.sendData(`http://${sessionData.url}/api/net/reconnect`, 'POST', data, {
- __RequestVerificationToken: sessionData.TokInfo,
- Cookie: `SessionId=${sessionData.SesInfo}`,
- });
- const json = await parser.parseStringPromise(resp);
+ const data = await huawei.doRSAEncrypt(sessionData, `1`);
+ const resp = await restCalls.sendDataRaw(`http://${sessionData.url}/api/net/reconnect`, 'POST', data, await getSessionHeaders(sessionData.url));
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const json = await parser.parseStringPromise(resp.data);
if (json.response !== 'OK') {
throw new Error(`Reconnecting error: ${JSON.stringify(json)}`);
}
@@ -41,10 +39,7 @@ export async function reconnect(sessionData: SessionData) {
export async function status(sessionData: SessionData, exportFile: string,
exportFormat: ExportFormat) {
- const resp = await restCalls.fetchData(`http://${sessionData.url}/api/monitoring/status`, 'GET', {
- __RequestVerificationToken: sessionData.TokInfo,
- Cookie: `SessionId=${sessionData.SesInfo}`,
- });
+ const resp = await restCalls.fetchData(`http://${sessionData.url}/api/monitoring/status`, 'GET', await getSessionHeaders(sessionData.url));
if (exportFormat !== 'hide') {
if (exportFormat === 'xml') {
await saveFile(exportFile, resp);
diff --git a/src/startSession.ts b/src/startSession.ts
index 855c070..f09bc76 100644
--- a/src/startSession.ts
+++ b/src/startSession.ts
@@ -2,6 +2,8 @@ import parser from 'xml2js';
import {restCalls} from "./utils/DefaultRestCalls";
+const huawei = require('../jslib/public');
+
export type SessionData = {
TokInfo: string,
SesInfo: string,
@@ -13,37 +15,123 @@ type SessionData0 = {
SesInfo: string
}
-// async function saveFile(data: SessionData) {
-// await fs.promises.writeFile(os.tmpdir() + '/huawei.tmp', JSON.stringify(data));
-// }
-//
-// async function readFile(): Promise {
-// try {
-// return JSON.parse(await fs.promises.readFile(os.tmpdir() + '/huawei.tmp', 'utf-8'));
-// } catch (e) {
-// console.error("read session data error", e);
-// await fs.promises.rm(os.tmpdir() + '/huawei.tmp');
-// throw e;
-// }
-// }
-//
-async function getSessionId(url: string): Promise {
+export async function hilinkLogin(url: string): Promise {
+ const resp = await restCalls.fetchData(`http://${url}/api/user/hilink_login`, 'GET');
+ const message = await parser.parseStringPromise(resp);
+ return message.response.hilink_login[0];
+}
+
+async function checkLogin(url: string, username: string, password: string|undefined): Promise {
+ const number = await hilinkLogin(url);
+ huawei.publicSession.login = number;
+ if (number === '1') {
+ if (!username) {
+ throw new Error('username is required');
+ }
+ if (!password) {
+ throw new Error('password is required');
+ }
+ }
+ return number === '1';
+}
+
+
+export async function logout(url: string) {
+ if (huawei.publicSession.login === '1') {
+ const resp = await restCalls.sendDataRaw(`http://${url}/api/user/logout`, 'POST',
+ `1`
+ , {
+ __RequestVerificationToken: `${huawei.publicSession.token2}`,
+ Cookie: `${huawei.publicSession.session}`,
+ _ResponseSource: 'Broswer',
+ });
+ huawei.publicSession.token2 = resp.headers.__requestverificationtoken;
+ const message = await parser.parseStringPromise(resp.data);
+ if (message.response !== 'OK') {
+ throw new Error(`Logout error: ${resp}`);
+ }
+ }
+}
+
+
+export async function login(url: string, user: string, password: string|undefined) {
+ if (await checkLogin(url, user, password)) {
+ const cryptoJS = huawei.CryptoJS;
+ const scram = cryptoJS.SCRAM();
+ const firstNonce = scram.nonce().toString();
+ const sd = await restCalls.fetchDataRaw(`http://${url}`, 'GET');
+ let header = sd.headers['set-cookie'] || [''];
+ const sd2 = await getSessionId0(url);
+
+ const sessionSec = header[0];
+ await getToken(url, sessionSec);
+ const resp = await restCalls.sendDataRaw(`http://${url}/api/user/challenge_login`, 'POST',
+ `${user}${firstNonce}1`,
+ {
+ __RequestVerificationToken: sd2.TokInfo,
+ Cookie: `${sessionSec}`,
+ _ResponseSource: 'Broswer',
+ DNT: 1,
+ });
+ const challengeLogin = await parser.parseStringPromise(resp.data);
+
+ const scarmSalt = cryptoJS.enc.Hex.parse(challengeLogin.response.salt[0]);
+ const iter = challengeLogin.response.iterations[0];
+ const finalNonce = challengeLogin.response.servernonce[0];
+ const authMsg = `${firstNonce},${finalNonce},${finalNonce}`;
+ const saltPassword = scram.saltedPassword(password, scarmSalt, iter).toString();
+ const serverKey = scram.serverKey(cryptoJS.enc.Hex.parse(saltPassword)).toString();
+ const clientProof = scram.clientProof(password, scarmSalt, iter, authMsg).toString();
+
+ const resp1 = await restCalls.sendDataRaw(`http://${url}/api/user/authentication_login`, 'POST',
+ `${clientProof}${finalNonce}`,
+ {
+ Cookie: `${sessionSec}`,
+ __RequestVerificationToken: resp.headers.__requestverificationtoken,
+ _ResponseSource: 'Broswer',
+ DNT: 1,
+ });
+ header = resp1.headers['set-cookie'] || [''];
+ huawei.publicSession.session = header[0].replace('; path=/; HttpOnly;', '');
+ huawei.publicSession.token1 = resp1.headers.__requestverificationtokenone;
+ huawei.publicSession.token2 = resp1.headers.__requestverificationtokentwo;
+ const data = await parser.parseStringPromise(resp1.data);
+ huawei.publicKey.publicKey =
+ {
+ encpubkeyn: data.response.rsan,
+ encpubkeye: data.response.rsae,
+ };
+ }
+}
+
+
+export async function getToken(url: string, cooke: string): Promise {
+ const resp = await restCalls.fetchDataRaw(`http://${url}/api/webserver/token`, 'GET',
+ {
+ _ResponseSource: 'Broswer',
+ DNT: 1,
+ Cookie: cooke,
+ });
+ const message = await parser.parseStringPromise(resp.data);
+
+ return {
+ token: message.response.token[0],
+ resp,
+ };
+}
+
+async function getSessionId0(url: string): Promise {
const resp = await restCalls.fetchData(`http://${url}/api/webserver/SesTokInfo`, 'GET');
const message = await parser.parseStringPromise(resp);
- return message.response;
-}
-//
-// export async function getCurrentSession() {
-// try {
-// const session: SessionData = await readFile();
-// await startSession(session.url);
-// return await readFile();
-// } catch (e) {
-// console.error("Session file does not exist or not valid please start a new session", e);
-// throw new Error("Session Does not exist")
-// }
-//
-// }
+ return {
+ TokInfo: message.response.TokInfo[0],
+ SesInfo: message.response.SesInfo[0],
+ };
+}
+
+async function getSessionId(url: string): Promise {
+ return getSessionId0(url);
+}
export async function startSession(url: string) {
const session0: SessionData0 = await getSessionId(url);
diff --git a/src/utils/DefaultRestCalls.ts b/src/utils/DefaultRestCalls.ts
index 1465324..728e245 100644
--- a/src/utils/DefaultRestCalls.ts
+++ b/src/utils/DefaultRestCalls.ts
@@ -1,4 +1,4 @@
-import fetch from 'axios';
+import fetch, {AxiosPromise} from 'axios';
import {HTTPMethod, RestCalls} from './restCalls';
@@ -15,6 +15,18 @@ class DefaultRestCalls implements RestCalls {
return ret.data;
}
+ async fetchDataRaw(url: string, method: HTTPMethod, headers?: any): Promise {
+ const ret = await fetch({
+ url,
+ method,
+ headers,
+ transformResponse: (req) => req,
+ withCredentials: true,
+ timeout: 29000,
+ });
+ return ret;
+ }
+
async sendData(url: string, method: HTTPMethod, data: string, headers?: any): Promise {
const ret = await fetch({
url,
@@ -28,6 +40,19 @@ class DefaultRestCalls implements RestCalls {
return ret.data;
}
+ async sendDataRaw(url: string, method: HTTPMethod, data: string, headers?: any): Promise {
+ const ret = await fetch({
+ url,
+ method,
+ data,
+ transformResponse: (req) => req,
+ headers,
+ withCredentials: true,
+ timeout: 29000,
+ });
+ return ret;
+ }
+
}
export const restCalls = new DefaultRestCalls();
diff --git a/src/utils/HuaweiUtils.ts b/src/utils/HuaweiUtils.ts
new file mode 100644
index 0000000..4d41715
--- /dev/null
+++ b/src/utils/HuaweiUtils.ts
@@ -0,0 +1,21 @@
+import {startSession} from "../startSession";
+
+const huawei = require('../../jslib/public');
+
+export async function getSessionHeaders(url:string):Promise {
+ if (huawei.publicSession.login === '1') {
+ return {
+ 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8;enc',
+ __RequestVerificationToken: `${huawei.publicSession.token2}`,
+ Cookie: `${huawei.publicSession.session}`,
+ _ResponseSource: 'Broswer',
+ };
+ } else {
+ const sessionData = await startSession(url);
+ return {
+ 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8;enc',
+ __RequestVerificationToken: sessionData.TokInfo,
+ Cookie: `SessionId=${sessionData.SesInfo}`,
+ };
+ }
+}
diff --git a/src/utils/restCalls.ts b/src/utils/restCalls.ts
index 57cef61..ccb079b 100644
--- a/src/utils/restCalls.ts
+++ b/src/utils/restCalls.ts
@@ -1,3 +1,5 @@
+import {AxiosPromise} from "axios";
+
export type HTTPMethod =
| 'get' | 'GET'
| 'delete' | 'DELETE'
@@ -12,5 +14,7 @@ export type HTTPMethod =
export interface RestCalls {
fetchData(url:string, method?:HTTPMethod, headers?:any):Promise;
+ fetchDataRaw(url:string, method?:HTTPMethod, headers?:any):Promise;
sendData(url:string, method:HTTPMethod, data:string, headers?:any):Promise;
+ sendDataRaw(url:string, method:HTTPMethod, data:string, headers?:any):Promise;
}