@nasl/cli 0.1.15 → 0.1.17

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.
Files changed (44) hide show
  1. package/build/nasl.bundle.js +4970 -4941
  2. package/dist/bin/nasl.mjs +243 -51
  3. package/dist/bin/nasl.mjs.map +1 -1
  4. package/dist/bin/naslc.mjs +196 -16
  5. package/dist/bin/naslc.mjs.map +1 -1
  6. package/dist/index.mjs +212 -49
  7. package/dist/index.mjs.map +1 -1
  8. package/out/apis/compileApi.d.ts.map +1 -1
  9. package/out/apis/compileApi.js +2 -4
  10. package/out/apis/compileApi.js.map +1 -1
  11. package/out/apis/createAppApi.js +1 -1
  12. package/out/apis/createAppApi.js.map +1 -1
  13. package/out/apis/createAxios.d.ts +7 -1
  14. package/out/apis/createAxios.d.ts.map +1 -1
  15. package/out/apis/createAxios.js +34 -5
  16. package/out/apis/createAxios.js.map +1 -1
  17. package/out/apis/openapi.d.ts +34 -0
  18. package/out/apis/openapi.d.ts.map +1 -0
  19. package/out/apis/openapi.js +114 -0
  20. package/out/apis/openapi.js.map +1 -0
  21. package/out/apis/transformApi.d.ts +1 -1
  22. package/out/apis/transformApi.d.ts.map +1 -1
  23. package/out/apis/transformApi.js +4 -6
  24. package/out/apis/transformApi.js.map +1 -1
  25. package/out/bin/nasl.js +63 -1
  26. package/out/bin/nasl.js.map +1 -1
  27. package/out/commands/check.d.ts.map +1 -1
  28. package/out/commands/check.js +1 -4
  29. package/out/commands/check.js.map +1 -1
  30. package/out/commands/compile.d.ts.map +1 -1
  31. package/out/commands/compile.js +1 -4
  32. package/out/commands/compile.js.map +1 -1
  33. package/out/commands/transform.d.ts.map +1 -1
  34. package/out/commands/transform.js +7 -19
  35. package/out/commands/transform.js.map +1 -1
  36. package/out/types/api.d.ts +8 -0
  37. package/out/types/api.d.ts.map +1 -1
  38. package/out/types/command.d.ts +1 -0
  39. package/out/types/command.d.ts.map +1 -1
  40. package/out/types/config.d.ts +6 -0
  41. package/out/types/config.d.ts.map +1 -1
  42. package/out/types/config.js +2 -2
  43. package/out/types/config.js.map +1 -1
  44. package/package.json +3 -1
package/dist/index.mjs CHANGED
@@ -11,7 +11,7 @@ import require$$5 from 'assert';
11
11
  import require$$3 from 'http';
12
12
  import require$$4 from 'https';
13
13
  import require$$0$6 from 'url';
14
- import require$$8 from 'crypto';
14
+ import crypto$1 from 'crypto';
15
15
  import http2 from 'http2';
16
16
  import zlib from 'zlib';
17
17
  import { spawn, spawnSync } from 'child_process';
@@ -24,10 +24,10 @@ import { resolve, join, relative, sep } from 'node:path';
24
24
  * 默认配置
25
25
  */
26
26
  const DEFAULT_CONFIG = {
27
- serverBaseURL: 'https://nasl.lcap.163yun.com/api/v1/nasl',
27
+ serverBaseURL: 'https://nasl.lcap.163yun.com',
28
28
  representation: 'NaturalTS',
29
29
  namespaceResolution: 'filename-as-namespace',
30
- ideVersion: '4.3',
30
+ ideVersion: '4.4',
31
31
  srcDir: 'src',
32
32
  outDir: 'out',
33
33
  };
@@ -27652,7 +27652,7 @@ function requireForm_data () {
27652
27652
  var parseUrl = require$$0$6.parse;
27653
27653
  var fs = require$$0$3;
27654
27654
  var Stream = stream$4.Stream;
27655
- var crypto = require$$8;
27655
+ var crypto = crypto$1;
27656
27656
  var mime = requireMimeTypes();
27657
27657
  var asynckit = requireAsynckit();
27658
27658
  var setToStringTag = /*@__PURE__*/ requireEsSetTostringtag();
@@ -28561,7 +28561,7 @@ const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {
28561
28561
  let str = '';
28562
28562
  const {length} = alphabet;
28563
28563
  const randomValues = new Uint32Array(size);
28564
- require$$8.randomFillSync(randomValues);
28564
+ crypto$1.randomFillSync(randomValues);
28565
28565
  for (let i = 0; i < size; i++) {
28566
28566
  str += alphabet[randomValues[i] % length];
28567
28567
  }
@@ -34346,14 +34346,199 @@ const {
34346
34346
  mergeConfig
34347
34347
  } = axios;
34348
34348
 
34349
- function createAxios(baseURL) {
34350
- return axios.create({
34349
+ // Unique ID creation requires a high quality random # generator. In the browser we therefore
34350
+ // require the crypto API and do not support built-in fallback to lower quality random number
34351
+ // generators (like Math.random()).
34352
+ let getRandomValues;
34353
+ const rnds8 = new Uint8Array(16);
34354
+ function rng() {
34355
+ // lazy load so that environments that need to polyfill have a chance to do so
34356
+ if (!getRandomValues) {
34357
+ // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
34358
+ getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
34359
+
34360
+ if (!getRandomValues) {
34361
+ throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
34362
+ }
34363
+ }
34364
+
34365
+ return getRandomValues(rnds8);
34366
+ }
34367
+
34368
+ /**
34369
+ * Convert array of 16 byte values to UUID string format of the form:
34370
+ * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
34371
+ */
34372
+
34373
+ const byteToHex = [];
34374
+
34375
+ for (let i = 0; i < 256; ++i) {
34376
+ byteToHex.push((i + 0x100).toString(16).slice(1));
34377
+ }
34378
+
34379
+ function unsafeStringify(arr, offset = 0) {
34380
+ // Note: Be careful editing this code! It's been tuned for performance
34381
+ // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
34382
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
34383
+ }
34384
+
34385
+ const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
34386
+ var native = {
34387
+ randomUUID
34388
+ };
34389
+
34390
+ function v4(options, buf, offset) {
34391
+ if (native.randomUUID && true && !options) {
34392
+ return native.randomUUID();
34393
+ }
34394
+
34395
+ options = options || {};
34396
+ const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
34397
+
34398
+ rnds[6] = rnds[6] & 0x0f | 0x40;
34399
+ rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
34400
+
34401
+ return unsafeStringify(rnds);
34402
+ }
34403
+
34404
+ /**
34405
+ * 构建签名字符串
34406
+ */
34407
+ function buildStringToSign(appKey, nonce, timestamp, secretKey) {
34408
+ return `${appKey}&${nonce}&${timestamp}&${secretKey}`;
34409
+ }
34410
+ /**
34411
+ * 生成 MD5 签名
34412
+ */
34413
+ function generateSignature(plainText) {
34414
+ return crypto$1.createHash('md5').update(plainText).digest('hex');
34415
+ }
34416
+ /**
34417
+ * 生成客户端签名信息
34418
+ * @param appKey AppKey
34419
+ * @param secretKey SecretKey
34420
+ * @returns 签名信息
34421
+ */
34422
+ function generateClientSignature(appKey, secretKey) {
34423
+ const timestamp = Math.floor(Date.now() / 1000).toString();
34424
+ const nonce = v4();
34425
+ const plainText = buildStringToSign(appKey, nonce, timestamp, secretKey);
34426
+ const signature = generateSignature(plainText);
34427
+ return {
34428
+ appKey,
34429
+ timestamp,
34430
+ nonce,
34431
+ signature,
34432
+ };
34433
+ }
34434
+ /**
34435
+ * 生成基础认证头
34436
+ * @param ak AppKey
34437
+ * @param sk SecretKey
34438
+ * @returns 基础认证头
34439
+ */
34440
+ function generateBaseHeaders(ak, sk) {
34441
+ const { timestamp, signature, nonce } = generateClientSignature(ak, sk);
34442
+ return {
34443
+ 'Content-Type': 'application/json',
34444
+ 'x-appKey': ak,
34445
+ 'x-timestamp': timestamp,
34446
+ 'x-nonce': nonce,
34447
+ 'x-signature': signature,
34448
+ };
34449
+ }
34450
+ /**
34451
+ * 获取租户的 signInfo
34452
+ * @param options 服务器选项
34453
+ * @param baseHeaders 基础认证头
34454
+ * @returns x-signInfo 值
34455
+ */
34456
+ async function fetchSignInfo(options, baseHeaders) {
34457
+ const tenantName = options.tenantName || 'defaulttenant';
34458
+ const userName = tenantName === 'defaulttenant' ? 'admin' : `${tenantName}-admin`;
34459
+ const data = {
34460
+ tenantName,
34461
+ userName,
34462
+ source: 'Normal',
34463
+ };
34464
+ const url = `${options.serverBaseURL}/openapi/v3/auth/getSignInfo`;
34465
+ try {
34466
+ const tempAxios = axios.create({
34467
+ headers: baseHeaders,
34468
+ timeout: 120000,
34469
+ });
34470
+ const response = await tempAxios.post(url, data);
34471
+ return response?.data?.result || null;
34472
+ }
34473
+ catch (error) {
34474
+ console.error('Error fetching sign info:', error.response?.data);
34475
+ return null;
34476
+ }
34477
+ }
34478
+ /**
34479
+ * 生成完整的认证头(包含 x-signInfo)
34480
+ * @param options 服务器选项
34481
+ * @returns 完整的认证头
34482
+ */
34483
+ async function generateCompleteHeaders(options) {
34484
+ const headers = {
34485
+ 'Content-Type': 'application/json',
34486
+ };
34487
+ const OPENAPI_AK = options.OPENAPI_AK || process.env.LCAP_OPENAPI_AK;
34488
+ const OPENAPI_SK = options.OPENAPI_SK || process.env.LCAP_OPENAPI_SK;
34489
+ // 如果没有提供 ak 和 sk,返回基础 headers
34490
+ if (!OPENAPI_AK || !OPENAPI_SK) {
34491
+ throw new Error(`配置了 useOPENAPI,但没有提供 OPENAPI_AK 和 OPENAPI_SK:
34492
+ - 可取消配置 useOPENAPI
34493
+ - 在 nasl.config.json 中配置 OPENAPI_AK 和 OPENAPI_SK,或者在环境变量中配置 LCAP_OPENAPI_AK 和 LCAP_OPENAPI_SK`);
34494
+ }
34495
+ // 生成基础认证头
34496
+ const baseHeaders = generateBaseHeaders(OPENAPI_AK, OPENAPI_SK);
34497
+ Object.assign(headers, baseHeaders);
34498
+ // 获取 signInfo
34499
+ const signInfo = await fetchSignInfo(options, headers);
34500
+ if (signInfo) {
34501
+ headers['x-signInfo'] = signInfo;
34502
+ }
34503
+ return headers;
34504
+ }
34505
+
34506
+ /**
34507
+ * 创建 Axios 实例
34508
+ * @param options 服务器选项,包含认证信息
34509
+ * @returns Axios 实例
34510
+ */
34511
+ async function createAxios(options) {
34512
+ // 如果需要鉴权,拼接 /openapi/v3/nasl;否则使用原始 URL
34513
+ const serverBaseURL = new URL(options.serverBaseURL).origin;
34514
+ const useOPENAPI = options.useOPENAPI || process.env.USE_LCAP_OPENAPI === 'true';
34515
+ const baseURL = useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
34516
+ // 如果需要鉴权,生成完整的认证头;否则只使用基础 headers
34517
+ const headers = useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
34518
+ console.log('本次服务调用方为:', baseURL);
34519
+ const instance = axios.create({
34351
34520
  baseURL,
34352
- headers: {
34353
- 'Content-Type': 'application/json',
34354
- },
34521
+ headers,
34355
34522
  timeout: 120000,
34356
34523
  });
34524
+ const oldPost = instance.post;
34525
+ instance.post = async (url, data, config) => {
34526
+ return oldPost(url, data, config).then((res) => {
34527
+ const data = res.data;
34528
+ if (data.code !== 200)
34529
+ throw new Error(JSON.stringify(data));
34530
+ return res;
34531
+ }).catch((err) => {
34532
+ // console.log(err.response ? err.response.data : err);
34533
+ if (err.response) {
34534
+ throw new Error(JSON.stringify(err.response.data));
34535
+ }
34536
+ else {
34537
+ throw err;
34538
+ }
34539
+ });
34540
+ };
34541
+ return instance;
34357
34542
  }
34358
34543
 
34359
34544
  function truncate(str, maxLength) {
@@ -34367,13 +34552,11 @@ function truncate(str, maxLength) {
34367
34552
  async function compileApi(fullNaturalTS, options) {
34368
34553
  // 这里需要调用实际的编译服务接口
34369
34554
  // 示例实现:
34370
- const axios = createAxios(options.serverBaseURL);
34555
+ const axios = await createAxios(options);
34371
34556
  const res = await axios.post(`/compile/tsx?ideVersion=${options.ideVersion}&needAnnotation=true`, fullNaturalTS, {
34372
34557
  headers: { 'Content-Type': 'text/plain' },
34373
34558
  });
34374
34559
  const data = res.data;
34375
- if (data.code !== 200)
34376
- throw new Error(data.message);
34377
34560
  const { bundle } = data.result;
34378
34561
  const fileMap = bundle.frontendBundle.files;
34379
34562
  const files = Object.keys(fileMap).map((key) => {
@@ -34401,7 +34584,7 @@ window.backendApp = app;
34401
34584
  * TODO: 实现具体的 API 调用逻辑
34402
34585
  */
34403
34586
  async function checkApi(fullNaturalTS, options) {
34404
- const axios = createAxios(options.serverBaseURL);
34587
+ const axios = await createAxios(options);
34405
34588
  const res = await axios.post(`/check/tsx?ideVersion=${options.ideVersion}`, fullNaturalTS, {
34406
34589
  headers: { 'Content-Type': 'text/plain' },
34407
34590
  });
@@ -34419,7 +34602,7 @@ async function checkApi(fullNaturalTS, options) {
34419
34602
  async function createAppSyncApi(fullNaturalTS, options) {
34420
34603
  const url = new URL(options.serverBaseURL);
34421
34604
  const origin = url.origin + '/app-ai-creator';
34422
- const axios = createAxios(origin);
34605
+ const axios = await createAxios({ serverBaseURL: origin});
34423
34606
  try {
34424
34607
  const res = await axios.post('/api/createAppSync', {
34425
34608
  fullNaturalTS,
@@ -34466,10 +34649,7 @@ async function compile(entry, options) {
34466
34649
  logger.info('正在调用编译服务...');
34467
34650
  try {
34468
34651
  const fullNaturalTS = composeToString(collectedFiles);
34469
- const outputFiles = await compileApi(fullNaturalTS, {
34470
- serverBaseURL: config.serverBaseURL,
34471
- ideVersion: config.ideVersion,
34472
- });
34652
+ const outputFiles = await compileApi(fullNaturalTS, config);
34473
34653
  logger.success('编译成功!');
34474
34654
  // 写入输出文件
34475
34655
  for (const file of outputFiles) {
@@ -34516,10 +34696,7 @@ async function check(entry, options) {
34516
34696
  result = error.message.trim();
34517
34697
  }
34518
34698
  if (!result && fullNaturalTS) {
34519
- result = (await checkApi(fullNaturalTS, {
34520
- serverBaseURL: config.serverBaseURL,
34521
- ideVersion: config.ideVersion,
34522
- })).trim();
34699
+ result = (await checkApi(fullNaturalTS, config)).trim();
34523
34700
  }
34524
34701
  const checkResult = {
34525
34702
  success: !result,
@@ -34859,15 +35036,13 @@ async function createAppInIde(entry, options) {
34859
35036
  * 编译 NASL 代码
34860
35037
  * TODO: 实现具体的 API 调用逻辑
34861
35038
  */
34862
- async function transformJson2FilesApi(jsonContent, options) {
35039
+ async function transformJson2FilesApi(json, options) {
34863
35040
  // 示例实现:
34864
- const axios = createAxios(options.serverBaseURL);
34865
- const res = await axios.post(`/transform/json2files?ideVersion=${options.ideVersion}`, jsonContent, {
34866
- headers: { 'Content-Type': 'text/plain' },
35041
+ const axios = await createAxios(options);
35042
+ const res = await axios.post(`/transform/json2files?ideVersion=${options.ideVersion}`, json, {
35043
+ headers: { 'Content-Type': 'application/json' },
34867
35044
  });
34868
35045
  const data = res.data;
34869
- if (data.code !== 200)
34870
- throw new Error(data.message);
34871
35046
  return data.result;
34872
35047
  }
34873
35048
 
@@ -34907,14 +35082,19 @@ const transformFns = {
34907
35082
  const projectRoot = getProjectRoot();
34908
35083
  logger.info(`项目根目录: ${projectRoot}`);
34909
35084
  logger.info(`源代码目录: ${config.srcDir}`);
35085
+ if (!libExports.existsSync(config.srcDir)) {
35086
+ logger.error(`当前目录下 ${config.srcDir} 目录不存在,请先创建`);
35087
+ logger.exit(1);
35088
+ }
34910
35089
  let jsonContent = '';
34911
35090
  if (!entry) {
34912
35091
  logger.warn('没有指定 JSON 文件路径,按照默认 IDE 版本的基础模板转换');
34913
35092
  }
34914
35093
  else {
34915
35094
  jsonContent = libExports.readFileSync(entry, 'utf-8');
35095
+ logger.info(`读取到 JSON 文件: ${entry}`);
34916
35096
  }
34917
- const files = await transformJson2FilesApi(jsonContent, {
35097
+ const files = await transformJson2FilesApi(jsonContent ? JSON.parse(jsonContent) : {}, {
34918
35098
  serverBaseURL: config.serverBaseURL,
34919
35099
  ideVersion: config.ideVersion,
34920
35100
  });
@@ -34928,25 +35108,8 @@ const transformFns = {
34928
35108
  * 将 src 中的文件转换成一个 JSON
34929
35109
  */
34930
35110
  async files2json(entry, options) {
34931
- const logger = options?.logger || defaultLogger;
34932
- // 收集需要处理的文件
34933
- const { collectedFiles, projectRoot } = await resolveNASLFiles(entry, logger, false, options?.verbose);
34934
- if (collectedFiles.length === 0) {
34935
- logger.error('未找到需要转换的文件');
34936
- logger.exit(1);
34937
- }
34938
- logger.info(`找到 ${collectedFiles.length} 个文件`);
34939
- // 转换为 JSON
34940
- logger.newLine();
34941
- logger.info('正在转换为 JSON...');
34942
- const jsonContent = JSON.stringify(collectedFiles, null, 2);
34943
- // 确定输出路径
34944
- const outputPath = options?.output
34945
- ? sysPath.resolve(projectRoot, options.output)
34946
- : sysPath.join(projectRoot, './files.json');
34947
- // 写入文件
34948
- writeFileWithLog(outputPath, jsonContent, logger);
34949
- logger.success(`JSON 文件已输出到: ${outputPath}`);
35111
+ options?.logger || defaultLogger;
35112
+ throw new Error('files2json 转换类型尚未实现');
34950
35113
  },
34951
35114
  };
34952
35115
  /**