biz-a-cli 2.3.8 → 2.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ import yargs from "yargs";
4
+ import axios from "axios";
5
+
6
+ const options = yargs(process.argv.slice(2))
7
+ .option("s", {
8
+ alias: "server",
9
+ describe: "Server URL (ex: https://biz-a.herokuapp.com or http://192.168.1.1 or https://finaapi.imamatek.com)",
10
+ type: "string",
11
+ demandOption: true
12
+ })
13
+ .option("i", {
14
+ alias: "dbindex",
15
+ describe: "database index",
16
+ type: "number",
17
+ demandOption: true
18
+ })
19
+ .option("n", {
20
+ alias: "appName",
21
+ describe: "Application name",
22
+ type: "string",
23
+ demandOption: true,
24
+ default: ""
25
+ })
26
+ .option("sub", {
27
+ alias: "subdomain",
28
+ describe: "Subdomain",
29
+ type: "string",
30
+ demandOption: false
31
+ })
32
+ .option("p", {
33
+ alias: "apiPort",
34
+ describe: "FINA API Port",
35
+ type: "string",
36
+ demandOption: false,
37
+ default : "212"
38
+ })
39
+ .argv;
40
+
41
+
42
+
43
+ const deleteApp = async () => {
44
+ try {
45
+ const baseUrl = 'fina/rest/TOrmMethod/%22deleteApp%22'
46
+ const url = options.sub ?
47
+ `${options.server}/hub/${baseUrl}?subdomain=${options.sub}` :
48
+ `${options.server}:${options.apiPort}/${baseUrl}`
49
+ const headers = {'Content-Type': 'text/plain'}
50
+ const deleteApps = options.appName.trim().replace(' ', '').toLowerCase()
51
+ const param = { _parameters: [options.dbindex, deleteApps] }
52
+ const res = await axios.post(url, param, { headers: headers });
53
+ if (res.data.success) {
54
+ console.log(`${deleteApps=='' ? 'All' : deleteApps} apps removed`)
55
+ } else {
56
+ console.error(res.data.error)
57
+ }
58
+ } catch (e) {
59
+ console.error(e.response?.data ? e.response.data : e)
60
+ }
61
+ }
62
+
63
+ deleteApp()
64
+
65
+ // delete all apps ==>> deleteApp -s https://finaapi.imamatek.com:1205 -i 2
66
+ // delete specific apps ==>> deleteApp -s https://finaapi.imamatek.com:1205 -i 2 -n "imamatek"
67
+ // delete multiple apps ==>> deleteApp -s https://finaapi.imamatek.com:1205 -i 2 -n "imamatek, spos"
package/bin/hub.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import yargs from 'yargs';
4
4
  import { io as ioc } from "socket.io-client";
@@ -77,6 +77,7 @@ app.use(express.json());
77
77
 
78
78
  app.set('args', argv);
79
79
 
80
+
80
81
  app.use('/cb', runCliScript);
81
82
 
82
83
  app.listen((argv.serverport || port), () => {
@@ -85,4 +86,8 @@ app.listen((argv.serverport || port), () => {
85
86
  //
86
87
 
87
88
  let socket = ioc(argv['server']);
88
- hubEvent(socket, argv);
89
+ hubEvent(socket, argv);
90
+
91
+ app.set('socket', socket)
92
+
93
+ export { app }
package/bin/hubEvent.js CHANGED
@@ -8,7 +8,7 @@ const IDLE_SOCKET_TIMEOUT_MILLISECONDS = 1000 * 30;
8
8
 
9
9
  // export default (argv) => {
10
10
  export default async (socket, argv) => new Promise((resolve, reject) => {
11
- socket.on('connect', () => {
11
+ const connectCb = () => {
12
12
  console.log(new Date() + ': connected to socket server');
13
13
  console.log(new Date() + ': requesting subdomain ' + argv['subdomain'] + ' via ' + argv['server']);
14
14
 
@@ -30,9 +30,8 @@ export default async (socket, argv) => new Promise((resolve, reject) => {
30
30
  resolve(url);
31
31
  }
32
32
  });
33
- });
34
-
35
- socket.on('incomingClient', (clientId) => {
33
+ }
34
+ const incomingHubCb = (clientId) => {
36
35
  console.log(clientId, 'incoming clientId')
37
36
  let client = net.connect(argv['port'], argv['hostname']);
38
37
 
@@ -58,9 +57,8 @@ export default async (socket, argv) => new Promise((resolve, reject) => {
58
57
  ss(socket).emit(clientId, s);
59
58
  s.end();
60
59
  });
61
- })
62
-
63
- socket.on('cli-req', (data, callback) => {
60
+ }
61
+ const cliReqCb = (data, callback) => {
64
62
  const { path, method, ...remainData } = data;
65
63
 
66
64
  Axios.request({
@@ -68,5 +66,8 @@ export default async (socket, argv) => new Promise((resolve, reject) => {
68
66
  url: `${process.env.HOST || 'http://localhost'}:${argv.serverport}/cb${path || ''}`,
69
67
  data: remainData
70
68
  }).subscribe(result => callback(result.data));
71
- });
69
+ }
70
+ socket.on('connect', connectCb);
71
+ socket.on('incomingClient', incomingHubCb)
72
+ socket.on('cli-req', cliReqCb );
72
73
  })
package/bin/index.js CHANGED
@@ -8,7 +8,7 @@ import { runInThisContext } from "vm";
8
8
  const options = yargs(process.argv.slice(2))
9
9
  .option("s", {
10
10
  alias: "server",
11
- describe: "Server URL",
11
+ describe: "Server URL (ex: https://biz-a.herokuapp.com or http://192.168.1.1 or https://finaapi.imamatek.com)",
12
12
  type: "string",
13
13
  demandOption: true
14
14
  })
@@ -30,13 +30,21 @@ const options = yargs(process.argv.slice(2))
30
30
  type: "string",
31
31
  demandOption: false
32
32
  })
33
+ .option("p", {
34
+ alias: "apiPort",
35
+ describe: "FINA API Port",
36
+ type: "string",
37
+ demandOption: false,
38
+ default : "212"
39
+ })
33
40
  .argv;
34
41
 
35
42
  const sendFile = async (filename, data) => {
36
43
  const baseUrl = 'fina/rest/TOrmMethod/%22setTemplate%22'
37
44
  const url = options.sub ?
38
45
  `${options.server}/hub/${baseUrl}?subdomain=${options.sub}` :
39
- `http://${options.server}:212/${baseUrl}`
46
+ // `http://${options.server}:212/${baseUrl}`
47
+ `${options.server}:${options.apiPort}/${baseUrl}`
40
48
 
41
49
  const headers = {
42
50
  'Content-Type': 'text/plain'
@@ -51,6 +59,8 @@ function getParam(funcName) {
51
59
  }
52
60
 
53
61
  function replacer(key, value) {
62
+ // note : cannot handle inline function such as :
63
+ // onClick: $event=>this.router.navigate(['../list', 'listspk'])
54
64
  if (typeof value == 'function') {
55
65
  let arr = value.toString().replace(/(\r\n|\n|\r)/gm, "°").split("°");
56
66
  if (arr.length < 3) throw 'Function must be minimal 3 lines';
@@ -76,7 +86,8 @@ const readTemplateFile = async (filename) => {
76
86
  } catch (error) {
77
87
  const fn = `file://${process.cwd()}\\${filename}`;
78
88
  const lib = await import(fn);
79
- result = JSON.stringify(lib.default(), replacer);
89
+ // result = JSON.stringify(lib.default(), replacer);
90
+ result = JSON.stringify((typeof lib.default=='function') ? lib.default() : lib.default, replacer);
80
91
  }
81
92
 
82
93
  return Buffer.from(result).toString('hex');
@@ -88,8 +99,10 @@ const readTemplateFile = async (filename) => {
88
99
  }
89
100
 
90
101
  const loopFiles = async (dir) => {
102
+ const uploadStart = performance.now()
91
103
  try {
92
104
  const files = await fs.readdir(dir);
105
+ let processedFile = 0
93
106
  for (const file of files) {
94
107
  //const p = path.join(dir, file);
95
108
  if (file == 'package.json' || file == 'package-lock.json') continue;
@@ -101,11 +114,13 @@ const loopFiles = async (dir) => {
101
114
  const res = await sendFile(file, data.toString('hex'));
102
115
  if (res.data.success) {
103
116
  console.log(`file: ${file} uploaded`);
117
+ processedFile++
104
118
  } else {
105
119
  console.error(res.data.error);
106
120
  }
107
121
  }
108
122
  }
123
+ console.log(`Finished uploading ${processedFile} files (${((performance.now()-uploadStart)/1000).toFixed(2)}s)`)
109
124
  } catch (e) {
110
125
  // console.error(e.response && e.response.data ? e.response.data : e);
111
126
  console.error(e.response?.data ? e.response.data : e);
@@ -113,3 +128,7 @@ const loopFiles = async (dir) => {
113
128
  }
114
129
 
115
130
  loopFiles('./');
131
+
132
+ // ex :
133
+ // uploadbiza -s https:\\finaapi.imamatek.com:1205 -i 2
134
+ // ..cli/bin/index.js -s https:\\finaapi.imamatek.com:1205 -i 2
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+
3
+ import yargs from "yargs";
4
+ import axios from "axios";
5
+ import { promises as fs } from "fs";
6
+ import { runInNewContext, runInThisContext } from "vm";
7
+ import uglify from "uglify-js";
8
+ import tar from "tar";
9
+ import {statSync, readFileSync} from 'fs';
10
+ import { verify, sign, privateDecrypt, constants as cryptoConstants, randomBytes, createCipheriv } from 'node:crypto';
11
+ import { basename } from "node:path"
12
+ import { env } from '../envs/env.js';
13
+ import { stringify } from "querystring";
14
+
15
+ const keyFolderPath = process.argv[1].substring(0, process.argv[1].lastIndexOf("\\bin")) + "\\key"
16
+
17
+ const options = yargs(process.argv.slice(2))
18
+ .option("s", {
19
+ alias: "server",
20
+ describe: "Server URL (ex: https://biz-a.herokuapp.com or http://192.168.1.1 or https://finaapi.imamatek.com)",
21
+ type: "string",
22
+ demandOption: true
23
+ })
24
+ .option("i", {
25
+ alias: "dbindex",
26
+ describe: "database index",
27
+ type: "number",
28
+ demandOption: true
29
+ })
30
+ .option("d", {
31
+ alias: "workingDir",
32
+ describe: "Path to templates directory",
33
+ type: "string",
34
+ demandOption: false,
35
+ default: process.cwd(),
36
+ })
37
+ .option("sub", {
38
+ alias: "subdomain",
39
+ describe: "Subdomain",
40
+ type: "string",
41
+ demandOption: false
42
+ })
43
+ .option("v", {
44
+ alias: "verbose",
45
+ describe: "Print info to console",
46
+ type: "boolean",
47
+ demandOption: false,
48
+ default: false,
49
+ })
50
+ .option("p", {
51
+ alias: "apiPort",
52
+ describe: "FINA API Port",
53
+ type: "string",
54
+ demandOption: false,
55
+ default : "212"
56
+ })
57
+ .argv;
58
+
59
+ function printInfo(msg){if (options.verbose) {console.log(msg)}}
60
+
61
+ function replacer(key, value) {
62
+ /*
63
+ // with line break
64
+ if (typeof value == 'function') {
65
+ let arr = value.toString().replace(/(\r\n|\n|\r)/gm, "°").split("°");
66
+ if (arr.length < 3) throw 'Function must be minimal 3 lines';
67
+ return [
68
+ 'window.Function',
69
+ getParam(arr[0]),
70
+ arr.slice(1, arr.length - 1)
71
+ ];
72
+ } else {
73
+ return value;
74
+ }
75
+ */
76
+
77
+ // without line break
78
+ if (typeof value == 'function') {
79
+ const fnScript = value.toString()
80
+ let params, body = ''
81
+ if (fnScript.indexOf('{')==-1) {
82
+ const arr = fnScript.split('=>')
83
+ params = arr[0]
84
+ body = arr.slice(1).join()
85
+ } else {
86
+ params = fnScript.split('{')[0]
87
+ body = fnScript.substring(fnScript.indexOf('{')+1, fnScript.lastIndexOf('}'))
88
+ }
89
+ params = params.replace(/(\s|=>|\(|\)|function)/gim, '')
90
+ printInfo(['window.Function', params, body])
91
+ return ['window.Function', params, body]
92
+ } else {
93
+ return value;
94
+ }
95
+ }
96
+
97
+ const getFileMinifiedData = async (fileName) => {
98
+ const dataFile = await fs.readFile(fileName);
99
+ printInfo(`===================\n${fileName.toUpperCase()}\n===================`)
100
+
101
+ let jsMinData = uglify.minify(dataFile.toString(), {compress: false, mangle: false}).code
102
+ jsMinData = jsMinData.replace('module.exports=get;', '') // Ex : at "executeBlockLib.js" of Imamatek App, will throw error. We need this line code for testing or debugging
103
+ const minifiedBuffer = Buffer.from(jsMinData)
104
+
105
+ printInfo(['Minify : \n', minifiedBuffer.toString()].join(''))
106
+ let stringifyData = ''
107
+ try {
108
+ printInfo('Running script with VM')
109
+ // const vmResult = runInThisContext(minifiedBuffer.toString())
110
+ const vmResult = runInNewContext(minifiedBuffer.toString()) // to handle if "let" function not using global scope
111
+ if (!vmResult) {
112
+ throw new Error('Undefined VM result')
113
+ }
114
+ printInfo('Array function :')
115
+ stringifyData = JSON.stringify((typeof vmResult=='function') ? vmResult() : vmResult, replacer)
116
+ printInfo(['Stringify : \n', stringifyData].join(''))
117
+ } catch (error) {
118
+ printInfo(error) // Do not log it as error
119
+ try {
120
+ printInfo('Running script with Import function')
121
+ const fn = `file://${process.cwd()}\\${fileName}`
122
+ const lib = await import(fn)
123
+ printInfo('Array function :')
124
+ stringifyData = JSON.stringify((typeof lib.default=='function') ? lib.default() : lib.default, replacer)
125
+ stringifyData = stringifyData.replace(/ /g,'') // remove trailing whitespace
126
+ // stringifyData = stringifyData.replace(/\\r\\n/g,'') // remove line break. We don't do this because "inline css" still requires line breaks
127
+ // console.log('RESULT =>', stringifyData)
128
+ printInfo(['Stringify : \n', stringifyData].join(''))
129
+ } catch (error){
130
+ throw(error)
131
+ }
132
+ }
133
+ printInfo('===================')
134
+ return Buffer.from(stringifyData)
135
+ }
136
+
137
+ const prepareKeys = async ()=>{
138
+ const data = Buffer.from(JSON.stringify({issuer: 'CLI', acquirer: 'Client'})).toString('base64')
139
+ const privateKey = readFileSync(`${keyFolderPath}\\cliPrivate.pem`)
140
+ const signature = sign('sha256', data, {key: privateKey, passphrase: 'Biz-A@cli', padding: cryptoConstants.RSA_PKCS1_PSS_PADDING}).toString('base64')
141
+ // const res = await axios.get('https://biz-a.herokuapp.com/api/issuerKey', {data, signature})
142
+ const res = await axios.get(env.BIZA_SERVER_LINK+'/api/issuerKey', {params: {data, signature}})
143
+ if ((res.data.data!=null) && verify('sha256', res.data.data, {key: readFileSync(`${keyFolderPath}\\serverPublic.pem`), padding: cryptoConstants.RSA_PKCS1_PSS_PADDING}, Buffer.from(res.data.signature, 'base64'))) {
144
+ const resData = JSON.parse(Buffer.from(res.data.data, 'base64').toString())
145
+ const decryptedAESKey = privateDecrypt({key: privateKey, passphrase: 'Biz-A@cli', padding: cryptoConstants.RSA_PKCS1_OAEP_PADDING}, Buffer.from(resData.issuer.key, 'base64')).toString()
146
+ const cliSignature = (signedData)=>sign('sha256', signedData, {key: privateKey, passphrase: 'Biz-A@cli', padding: cryptoConstants.RSA_PKCS1_PSS_PADDING}).toString('base64')
147
+ const acquirerData = Buffer.from(JSON.stringify(resData.acquirer)).toString('base64')
148
+ const signature = cliSignature(acquirerData)
149
+ return {encryptKey: decryptedAESKey, metadata: {acquirer: {data: acquirerData, signature}}}
150
+ }
151
+ else {
152
+ return null
153
+ }
154
+ }
155
+
156
+ const encryptIt = (data, encryptKey)=>{
157
+ const initializeVector = randomBytes(16) // "iv" is unique for each template file
158
+ const cipher = createCipheriv('aes-256-cbc', Buffer.from(encryptKey, 'base64'), initializeVector)
159
+ return Buffer.concat([initializeVector, cipher.update(data), cipher.final()]) // we put "iv" at beginning of cipherText, seperate it when doing decryption
160
+ }
161
+
162
+ const uploadTemplateApps = async () => {
163
+ process.chdir(options.workingDir)
164
+ try {
165
+ const bundlingStart = performance.now()
166
+ const rootFolder = './upload/'
167
+ const bundleName = basename(process.cwd()).trim().replace(' ', '').toLowerCase()
168
+ const bundleFolder = rootFolder+bundleName+'/'
169
+ const files = (await fs.readdir(process.cwd())).filter(fileName=>{
170
+ const stat = statSync(fileName)
171
+ return stat.isFile() && (stat.size>0) && ((fileName.split('.').pop().toLowerCase().match(/^(js)$/) || (fileName.toLowerCase()=='menu.json')))
172
+ })
173
+ if (files.length>0) {
174
+ const keys = await prepareKeys()
175
+ let processedFile = 0
176
+ await fs.rm(rootFolder, {force: true, recursive: true})
177
+ await fs.mkdir(bundleFolder, {recursive: true})
178
+ for (const file of files) {
179
+ const fileName = file.toLowerCase();
180
+ // if (['finalib.js', 'solib.js'].indexOf(fileName)==-1) {continue}
181
+ const minifiedData = await getFileMinifiedData(fileName);
182
+ const encryptedData = encryptIt(minifiedData, keys.encryptKey)
183
+ /*
184
+ hex => 2 char = 1 bytes => can be encrypted
185
+ base64 => 4 char = 3 bytes => can be encrypted. Smaller size compare to Hex
186
+ utf8 => 1 char = 1 - 4 bytes => can not be encrypted, encryption need precise bytes per Character. Smallest Size compare to Hex and base64
187
+ */
188
+ if (fileName=='menu.json') {
189
+ keys.metadata['menu'] = encryptedData.toString('base64')
190
+ } else {
191
+ fs.writeFile(bundleFolder+fileName, encryptedData.toString('base64'))
192
+ }
193
+ processedFile++
194
+ }
195
+
196
+ // compressor
197
+ const bundleFile = `${rootFolder}${bundleName}.tgz`
198
+ tar.c({file: bundleFile, cwd: bundleFolder, gzip: {level:9}, portable: true, sync: true}, await fs.readdir(bundleFolder))
199
+ await fs.rm(bundleFolder, {force: true, recursive: true})
200
+ console.log(`Finished packing ${processedFile} files into "${bundleFile}" (${((performance.now()-bundlingStart)/1000).toFixed(2)}s)`)
201
+
202
+ // send to FINAPI
203
+ const uploadingStart = performance.now()
204
+ const data = (await fs.readFile(bundleFile)).toString('base64') // *.tgz to base64String
205
+ const baseUrl = 'fina/rest/TOrmMethod/%22setApp%22'
206
+ const url = options.sub ?
207
+ `${options.server}/hub/${baseUrl}?subdomain=${options.sub}` :
208
+ `${options.server}:${options.apiPort}/${baseUrl}`
209
+ const headers = {'Content-Type': 'text/plain'}
210
+ const param = { _parameters: [options.dbindex, bundleName, data, keys.metadata] }
211
+ const res = await axios.post(url, param, { headers: headers });
212
+ if (res.data.success) {
213
+ console.log(`Finished uploading "${bundleFile}" (${((performance.now()-uploadingStart)/1000).toFixed(2)}s)`)
214
+ await fs.rm(rootFolder, {force: true, recursive: true})
215
+ } else {
216
+ console.error(res.data.error)
217
+ }
218
+ }
219
+ } catch (e) {
220
+ console.error(e.response?.data ? e.response.data : e)
221
+ }
222
+ }
223
+
224
+ uploadTemplateApps()
225
+
226
+ // uploadApp -s https://finaapi.imamatek.com:1205 -i 2 -d "C:\agung\source\biza templates\imamatek"
227
+ // ..\cli\bin\uploadApp.js -s https://finaapi.imamatek.com:1205 -i 2 -d "C:\agung\source\biza templates\imamatek"
228
+ // uploadApp -s https://finaapi.imamatek.com:1205 -i 2 -d ".\imamatek"
@@ -6,10 +6,14 @@ export function getInputScript(req) {
6
6
  return {
7
7
  data: {
8
8
  arguments: args,
9
- body: req.body.body
9
+ body: req.body.body,
10
+ path: req.path,
11
+ query: req.body.query,
12
+ headers: req.body.headers,
13
+ socket : req.app.settings.socket,
10
14
  },
11
15
  selectedConfig: {
12
- API_URL: `http://${args.hostname}:${args.port}`,
16
+ url: `http://${args.hostname}:${args.port}`,
13
17
  dbindex: args.dbindex,
14
18
  subdomain: args.subdomain
15
19
  }
@@ -17,13 +21,16 @@ export function getInputScript(req) {
17
21
  }
18
22
 
19
23
  export async function runCliScript(req, res) {
24
+
20
25
  const { data, selectedConfig } = getInputScript(req);
21
-
26
+ // console.log('runCliScript data', data)
22
27
  loadCliScript(selectedConfig, req.body.query).subscribe({
23
28
  next: async script => {
24
29
  let functions = extractFunctionScript(script);
25
30
  if (functions) {
26
- res.send(await functions.onInit(data));
31
+ let respon = await functions.onInit(data);
32
+ // console.log('respon cb', respon)
33
+ res.send(respon);
27
34
  console.log(`Run Callback Successfully!`);
28
35
  } else {
29
36
  res.send('CLI Script does not exist.');
package/envs/env.dev.js CHANGED
@@ -5,6 +5,7 @@ export const envDev = {
5
5
  CDM_MONGO_LINK: 'mongodb+srv://imm_cdm:' +
6
6
  encodeURIComponent('imm@2019') + '@imm-cdm-dev.rf6wr.mongodb.net/?retryWrites=true&w=majority',
7
7
  COMPANY_REGISTER: 'companyregister-dev',
8
- BIZA_SERVER_LINK: 'https://biz-a-dev-41e7c93a25e5.herokuapp.com'
8
+ // BIZA_SERVER_LINK: 'https://biz-a-dev-41e7c93a25e5.herokuapp.com'
9
+ BIZA_SERVER_LINK: 'https://www.ptimf.id/biz-a-dev.com'
9
10
  // BIZA_SERVER_LINK: 'http://localhost:3000'
10
11
  };
@@ -0,0 +1,54 @@
1
+ -----BEGIN ENCRYPTED PRIVATE KEY-----
2
+ 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
54
+ -----END ENCRYPTED PRIVATE KEY-----
@@ -0,0 +1,14 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsygI0CgE30zwazWnM50i
3
+ otXV3FvisoG1oIlpCquhif6aJYCREy6gnn+RFxspMcrCX6dVGjWyEHC9yznOzzO+
4
+ xsPEtzyDWMtqxbfx1rTwVB60qBv1ewvGOWv9KBv8xaMyC+BreLL/iUTH3HjJLV5/
5
+ hcxYibMfGWzYaLAFnHSNwtDfTeraK2MEVjMreMR5tThCHbp/nGIUAWYp9Z/jj09X
6
+ 6mbNHT4DL0SRwR7SKFmMmGmgxi8M4Qp6tRYYpx7QvmaXq8KDWL3cIvVwTBW6H+KW
7
+ yhhWvqyGZ9OKV5OLVzdSmeEesV3eTxv6EgRDIoODSn4MLIwHuIGOlRgeuNahm4nB
8
+ MwVkOBDMaf1k8bHrSf+CY7oyf0f1nlxdwZv5kmixEcifL8Ie7XhKO076duwpKyda
9
+ vuv5QdsCJ0aO3Kqq/F1QUYYJgtVsERKE+OFCjLaetqQXy+wlt+naAsUSKsNDBq0h
10
+ XsZPZZxP5+nNjkRyNtujz70iOm1s/oPmkJ1MeqLBFonCW8tkbwKbc2c+iMwXLqE7
11
+ g2TBHzpvJmW3V9h9nJkdits37mi8rP1DQHlhEH/PL6Rd6q+XJ4Owze0eCZOWaMD2
12
+ 8FdeodSiQd7mDZssooGsFvjjklo9PMnQfwDJXWwc2GoyCzfJo3KKpeKT/4HuVtfn
13
+ zyxyuV/3sV3hnO7jvuNSILECAwEAAQ==
14
+ -----END PUBLIC KEY-----
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "biz-a-cli",
3
3
  "nameDev": "biz-a-cli-dev",
4
- "version": "2.3.8",
4
+ "version": "2.3.9",
5
5
  "versionDev": "0.0.27",
6
6
  "description": "",
7
7
  "main": "bin/index.js",
@@ -22,7 +22,9 @@
22
22
  "uploadbiza": "bin/index.js",
23
23
  "proxy": "bin/proxy.js",
24
24
  "hub": "bin/hub.js",
25
- "watcher": "bin/watcher.js"
25
+ "watcher": "bin/watcher.js",
26
+ "uploadapp": "bin/uploadApp.js",
27
+ "deleteapp": "bin/deleteApp.js"
26
28
  },
27
29
  "dependencies": {
28
30
  "axios": "^1.6.8",
@@ -36,6 +38,8 @@
36
38
  "socket.io-client": "^4.7.5",
37
39
  "socket.io-stream": "^0.9.1",
38
40
  "web-push": "^3.6.7",
41
+ "tar": "^6.2.0",
42
+ "uglify-js": "^3.17.4",
39
43
  "yargs": "^17.7.2"
40
44
  },
41
45
  "devDependencies": {
@@ -45,4 +49,4 @@
45
49
  "jest": {
46
50
  "transform": {}
47
51
  }
48
- }
52
+ }
@@ -20,21 +20,34 @@ describe('callback test', () => {
20
20
 
21
21
  const request = {
22
22
  app: { settings: { args: args } },
23
- body: { body: { body1: 'value1' } }
23
+ body: {
24
+ body: { body1: 'value1' },
25
+ headers:{connection:'keep-alive'}
26
+ },
27
+ path:'pqr',
28
+
24
29
  }
25
30
 
26
31
  expect(getInputScript(request)).toStrictEqual({
27
32
  data: {
28
33
  arguments: args,
29
- body: { body1: 'value1' }
34
+ body: { body1: 'value1' },
35
+ path:'pqr',
36
+ query:undefined,
37
+ headers:{
38
+ connection:'keep-alive'
39
+ },
40
+ socket:undefined,
41
+
30
42
  },
31
43
  selectedConfig: {
32
- API_URL: 'http://localhost:212',
44
+ url: 'http://localhost:212',
33
45
  dbindex: 2,
34
46
  subdomain: 'abc'
35
47
  }
36
48
  });
37
49
  });
38
50
 
51
+
39
52
  })
40
53
 
package/tests/hub.test.js CHANGED
@@ -9,104 +9,106 @@ import { Axios } from "axios-observable";
9
9
  let socketsBySubdomain = {};
10
10
 
11
11
  const createSocket2CLI = (socket) => {
12
- return (subdomain, responseCb) => {
13
- const responseCallback = (error) => { if (responseCb) responseCb(error) }
14
- let subdomainStr = subdomain.toString();
12
+ return (subdomain, responseCb) => {
13
+ const responseCallback = (error) => { if (responseCb) responseCb(error) }
14
+ let subdomainStr = subdomain.toString();
15
15
 
16
- socketsBySubdomain[subdomainStr] = socket;
17
- socket.subdomain = subdomainStr;
18
- // console.log(new Date() + ': ' + subdomainStr + ' registered successfully');
16
+ socketsBySubdomain[subdomainStr] = socket;
17
+ socket.subdomain = subdomainStr;
18
+ // console.log(new Date() + ': ' + subdomainStr + ' registered successfully');
19
19
 
20
- responseCallback(null);
21
- }
20
+ responseCallback(null);
21
+ }
22
22
  }
23
23
 
24
24
  const deleteSubdomain = (socket) => () => {
25
- if (socket.subdomain) {
26
- delete socketsBySubdomain[socket.subdomain];
27
- console.log(new Date() + ': ' + socket.subdomain + ' unregistered');
28
- }
25
+ if (socket.subdomain) {
26
+ delete socketsBySubdomain[socket.subdomain];
27
+ console.log(new Date() + ': ' + socket.subdomain + ' unregistered');
28
+ }
29
29
  }
30
30
 
31
31
  const toPromise = (cb) => new Promise((resolve, reject) => {
32
- cb(resolve)
33
- setTimeout(() => reject(new Error('timeout')), 1000)
32
+ cb(resolve)
33
+ setTimeout(() => reject(new Error('timeout')), 1000)
34
34
  })
35
35
 
36
36
  describe('cli req test', () => {
37
- let io, port;
38
- const startSocket = function startSocket(server) {
39
- let io = new Server(server);
40
- io.on('connection', (socket) => {
41
- // console.log('socket client connect')
42
- socket.on('createTunnel', createSocket2CLI(socket));
43
- socket.on('disconnect', deleteSubdomain(socket));
44
- });
45
-
46
- return io;
47
- }
48
-
49
- beforeAll((done) => {
50
- const httpServer = createServer()
51
- io = startSocket(httpServer)
52
-
53
- httpServer.listen(async () => {
54
- port = httpServer.address().port;
55
- done()
56
- })
57
- })
58
-
59
- afterAll(() => {
60
- io.close();
61
- })
62
-
63
- test('request to cli', async () => {
64
- let mockedRequest = jest.spyOn(Axios, 'request').mockReturnValue(of({ data: 'OK' }));
65
-
66
- let socket;
67
- try {
68
- socket = ioc(`http://localhost:${port}`);
69
- await hubEvent(socket, {
70
- server: `http://localhost:${port}`,
71
- subdomain: 'scy',
72
- hostname: 'localhost',
73
- port: 212,
74
- serverport: 3002
75
- });
76
-
77
- let result = await toPromise(resolve => socketsBySubdomain['scy'].emit(
78
- 'cli-req', {
79
- // path: '/a/b',
80
- method: 'POST',
81
- query: { subdomain: 'abc' }, body: { data: 'xyz' }
82
- }, cb => resolve(cb)
83
- ))
84
-
85
- expect(result).toStrictEqual('OK');
86
- expect(mockedRequest).toHaveBeenCalledWith({
87
- data: { body: { data: "xyz" }, query: { subdomain: "abc" } },
88
- method: "POST",
89
- url: "http://localhost:3002/cb"
90
- });
91
-
92
- result = await toPromise(resolve => socketsBySubdomain['scy'].emit(
93
- 'cli-req', {
94
- path: '/a/b',
95
- method: 'POST',
96
- query: { subdomain: 'abc' }, body: { data: 'xyz' }
97
- }, cb => resolve(cb)
98
- ))
99
-
100
- expect(result).toStrictEqual('OK');
101
- expect(mockedRequest).toHaveBeenCalledWith({
102
- data: { body: { data: "xyz" }, query: { subdomain: "abc" } },
103
- method: "POST",
104
- url: "http://localhost:3002/cb/a/b",
105
- });
106
-
107
- socket.disconnect();
108
- } catch (error) {
109
- console.log(error);
37
+ let io, port;
38
+ const startSocket = function startSocket(server) {
39
+ let io = new Server(server);
40
+ io.on('connection', (socket) => {
41
+ // console.log('socket client connect')
42
+ socket.on('createTunnel', createSocket2CLI(socket));
43
+ socket.on('disconnect', deleteSubdomain(socket));
44
+ });
45
+
46
+ return io;
110
47
  }
111
- })
48
+
49
+ beforeAll((done) => {
50
+ const httpServer = createServer()
51
+ io = startSocket(httpServer)
52
+
53
+ httpServer.listen(async () => {
54
+ port = httpServer.address().port;
55
+ done()
56
+ })
57
+ })
58
+
59
+ afterAll(() => {
60
+ io.close();
61
+ })
62
+
63
+ test('request to cli', async () => {
64
+ let mockedRequest = jest.spyOn(Axios, 'request').mockReturnValue(of({ data: 'OK' }));
65
+
66
+ let socket;
67
+ try {
68
+ socket = ioc(`http://localhost:${port}`);
69
+ await hubEvent(socket, {
70
+ server: `http://localhost:${port}`,
71
+ subdomain: 'scy',
72
+ hostname: 'localhost',
73
+ port: 212,
74
+ serverport: 3002
75
+ });
76
+
77
+ let result = await toPromise(resolve => socketsBySubdomain['scy'].emit(
78
+ 'cli-req',
79
+ {
80
+ // path: '/a/b',
81
+ method: 'POST',
82
+ query: { subdomain: 'abc' }, body: { data: 'xyz' }
83
+ },
84
+ cb => resolve(cb)
85
+ ))
86
+
87
+ expect(result).toStrictEqual('OK');
88
+ expect(mockedRequest).toHaveBeenCalledWith({
89
+ data: { body: { data: "xyz" }, query: { subdomain: "abc" } },
90
+ method: "POST",
91
+ url: "http://localhost:3002/cb"
92
+ });
93
+
94
+ result = await toPromise(resolve => socketsBySubdomain['scy'].emit(
95
+ 'cli-req', {
96
+ path: '/a/b',
97
+ method: 'POST',
98
+ query: { subdomain: 'abc' }, body: { data: 'xyz' }
99
+ }, cb => resolve(cb)
100
+ ))
101
+
102
+ expect(result).toStrictEqual('OK');
103
+ expect(mockedRequest).toHaveBeenCalledWith({
104
+ data: { body: { data: "xyz" }, query: { subdomain: "abc" } },
105
+ method: "POST",
106
+ url: "http://localhost:3002/cb/a/b",
107
+ });
108
+
109
+ socket.disconnect();
110
+ } catch (error) {
111
+ console.log(error);
112
+ }
113
+ })
112
114
  })