casualos 3.3.8-alpha.10146812598 → 3.3.8-alpha.10185283421

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 (2) hide show
  1. package/dist/cli.js +336 -19
  2. package/package.json +4 -4
package/dist/cli.js CHANGED
@@ -94691,7 +94691,7 @@ var trace = TraceAPI.getInstance();
94691
94691
  function hashLowEntropyPasswordWithSalt2(password, salt) {
94692
94692
  const tracer = trace.getTracer(
94693
94693
  "InstrumentedHashHelpers",
94694
- false ? void 0 : "v3.3.8-alpha.10146812598"
94694
+ false ? void 0 : "v3.3.8-alpha.10185283421"
94695
94695
  );
94696
94696
  return tracer.startActiveSpan(
94697
94697
  "hashLowEntropyPasswordWithSalt",
@@ -94709,7 +94709,7 @@ function hashLowEntropyPasswordWithSalt2(password, salt) {
94709
94709
  function hashHighEntropyPasswordWithSalt2(password, salt) {
94710
94710
  const tracer = trace.getTracer(
94711
94711
  "InstrumentedHashHelpers",
94712
- false ? void 0 : "v3.3.8-alpha.10146812598"
94712
+ false ? void 0 : "v3.3.8-alpha.10185283421"
94713
94713
  );
94714
94714
  return tracer.startActiveSpan(
94715
94715
  "hashHighEntropyPasswordWithSalt",
@@ -94727,7 +94727,7 @@ function hashHighEntropyPasswordWithSalt2(password, salt) {
94727
94727
  function verifyPasswordAgainstHashes2(password, salt, hashes) {
94728
94728
  const tracer = trace.getTracer(
94729
94729
  "InstrumentedHashHelpers",
94730
- false ? void 0 : "v3.3.8-alpha.10146812598"
94730
+ false ? void 0 : "v3.3.8-alpha.10185283421"
94731
94731
  );
94732
94732
  return tracer.startActiveSpan(
94733
94733
  "verifyPasswordAgainstHashes",
@@ -101321,7 +101321,7 @@ var import_semantic_conventions = __toESM(require_src3());
101321
101321
  function traced(tracerName, options = {}, metricOptions = {}) {
101322
101322
  const tracer = trace.getTracer(
101323
101323
  tracerName,
101324
- false ? void 0 : "v3.3.8-alpha.10146812598"
101324
+ false ? void 0 : "v3.3.8-alpha.10185283421"
101325
101325
  );
101326
101326
  return function(target, propertyKey, descriptor) {
101327
101327
  const originalMethod = descriptor.value;
@@ -101399,7 +101399,7 @@ function getHistogram(meter) {
101399
101399
  }
101400
101400
  return metrics.getMeter(
101401
101401
  meter.meter,
101402
- false ? void 0 : "v3.3.8-alpha.10146812598"
101402
+ false ? void 0 : "v3.3.8-alpha.10185283421"
101403
101403
  ).createHistogram(meter.name, meter.options);
101404
101404
  }
101405
101405
  function getCounter(meter) {
@@ -101408,7 +101408,7 @@ function getCounter(meter) {
101408
101408
  }
101409
101409
  return metrics.getMeter(
101410
101410
  meter.meter,
101411
- false ? void 0 : "v3.3.8-alpha.10146812598"
101411
+ false ? void 0 : "v3.3.8-alpha.10185283421"
101412
101412
  ).createCounter(meter.name, meter.options);
101413
101413
  }
101414
101414
  function traceHttpResponse(options = {}) {
@@ -106769,7 +106769,7 @@ var WebsocketController = class {
106769
106769
  connection.inst,
106770
106770
  connection.branch
106771
106771
  );
106772
- if (branch2.temporary) {
106772
+ if (branch2?.temporary) {
106773
106773
  await this._temporaryStore.deleteBranch(
106774
106774
  connection.recordName,
106775
106775
  connection.inst,
@@ -111900,7 +111900,7 @@ var RecordsServer = class {
111900
111900
  this._loomController = loomController;
111901
111901
  this._tracer = trace.getTracer(
111902
111902
  "RecordsServer",
111903
- false ? void 0 : "v3.3.8-alpha.10146812598"
111903
+ false ? void 0 : "v3.3.8-alpha.10185283421"
111904
111904
  );
111905
111905
  this._procedures = this._createProcedures();
111906
111906
  this._setupRoutes();
@@ -112464,6 +112464,36 @@ var RecordsServer = class {
112464
112464
  updateFile: procedure().origins("api").http("PUT", "/api/v2/records/file").inputs(UPDATE_FILE_SCHEMA).handler(
112465
112465
  async (data, context) => this._updateFile(data, context)
112466
112466
  ),
112467
+ scanFileForModeration: procedure().origins("account").http("POST", "/api/v2/records/file/scan").inputs(
112468
+ z.object({
112469
+ recordName: RECORD_NAME_VALIDATION,
112470
+ fileName: z.string().min(1)
112471
+ })
112472
+ ).handler(async (input2, context) => {
112473
+ const validation = await this._validateSessionKey(
112474
+ context.sessionKey
112475
+ );
112476
+ if (validation.success === false) {
112477
+ if (validation.errorCode === "no_session_key") {
112478
+ return NOT_LOGGED_IN_RESULT;
112479
+ }
112480
+ return validation;
112481
+ }
112482
+ if (!isSuperUserRole(validation.role)) {
112483
+ return {
112484
+ success: false,
112485
+ errorCode: "not_authorized",
112486
+ errorMessage: "You are not authorized to perform this action."
112487
+ };
112488
+ }
112489
+ const recordName = input2.recordName;
112490
+ const fileName = input2.fileName;
112491
+ const result = await this._moderationController.scanFile({
112492
+ recordName,
112493
+ fileName
112494
+ });
112495
+ return result;
112496
+ }),
112467
112497
  eraseData: procedure().origins("api").http("DELETE", "/api/v2/records/data").inputs(ERASE_DATA_SCHEMA).handler(
112468
112498
  async (data, context) => this._baseEraseRecordData(this._data, data, context)
112469
112499
  ),
@@ -113734,8 +113764,8 @@ var RecordsServer = class {
113734
113764
  return {
113735
113765
  success: true,
113736
113766
  ...metadata,
113737
- version: true ? "v3.3.8-alpha.10146812598" : void 0,
113738
- versionHash: true ? "fa305e70ffae2a7db952ef49002955d89d58cb46" : void 0
113767
+ version: true ? "v3.3.8-alpha.10185283421" : void 0,
113768
+ versionHash: true ? "3ac65fe7f13ca98e64cc50e25e66b0f98a228436" : void 0
113739
113769
  };
113740
113770
  })
113741
113771
  };
@@ -126561,10 +126591,11 @@ var import_lodash23 = __toESM(require_lodash());
126561
126591
  // ../aux-records/ModerationController.ts
126562
126592
  var TRACE_NAME16 = "ModerationController";
126563
126593
  var ModerationController = class {
126564
- constructor(store, config2, messenger) {
126594
+ constructor(store, config2, messenger, jobProvider) {
126565
126595
  this._store = store;
126566
126596
  this._config = config2;
126567
126597
  this._messenger = messenger;
126598
+ this._jobProvider = jobProvider;
126568
126599
  }
126569
126600
  async reportInst(request) {
126570
126601
  try {
@@ -126626,10 +126657,266 @@ var ModerationController = class {
126626
126657
  };
126627
126658
  }
126628
126659
  }
126660
+ async scheduleModerationScans() {
126661
+ try {
126662
+ if (!this._jobProvider) {
126663
+ console.warn(
126664
+ "[ModerationController] No job provider available to schedule moderation scans."
126665
+ );
126666
+ return {
126667
+ success: false,
126668
+ errorCode: "not_supported",
126669
+ errorMessage: "This operation is not supported."
126670
+ };
126671
+ }
126672
+ const config2 = await this._config.getModerationConfig();
126673
+ if (!config2) {
126674
+ return {
126675
+ success: false,
126676
+ errorCode: "not_supported",
126677
+ errorMessage: "This operation is not supported."
126678
+ };
126679
+ }
126680
+ const jobs = [];
126681
+ if (config2.jobs?.files?.enabled) {
126682
+ console.log(
126683
+ "[ModerationController] Starting file moderation job..."
126684
+ );
126685
+ let filter3 = {};
126686
+ if (config2.jobs.files.fileExtensions) {
126687
+ filter3.keyNameConstraint = {
126688
+ matchAnySuffix: config2.jobs.files.fileExtensions
126689
+ };
126690
+ }
126691
+ const lastFileJob = await this._store.findMostRecentJobOfType(
126692
+ "files"
126693
+ );
126694
+ if (lastFileJob) {
126695
+ filter3.createdAfterMs = lastFileJob.createdAtMs;
126696
+ }
126697
+ const job = await this._jobProvider.startFilesJob(filter3);
126698
+ await this._store.addModerationJob(job);
126699
+ jobs.push(job);
126700
+ console.log(
126701
+ "[ModerationController] File moderation job started:",
126702
+ job
126703
+ );
126704
+ }
126705
+ return {
126706
+ success: true,
126707
+ jobs
126708
+ };
126709
+ } catch (err) {
126710
+ const span = trace.getActiveSpan();
126711
+ span?.recordException(err);
126712
+ span?.setStatus({ code: SpanStatusCode.ERROR });
126713
+ console.error(
126714
+ "[ModerationController] Failed to start moderation jobs:",
126715
+ err
126716
+ );
126717
+ return {
126718
+ success: false,
126719
+ errorCode: "server_error",
126720
+ errorMessage: "A server error occurred."
126721
+ };
126722
+ }
126723
+ }
126724
+ async scanFile(request) {
126725
+ try {
126726
+ if (!this._jobProvider) {
126727
+ console.warn(
126728
+ "[ModerationController] No job provider available to scan files."
126729
+ );
126730
+ return {
126731
+ success: false,
126732
+ errorCode: "not_supported",
126733
+ errorMessage: "This operation is not supported."
126734
+ };
126735
+ }
126736
+ const config2 = await this._config.getModerationConfig();
126737
+ if (!config2) {
126738
+ return {
126739
+ success: false,
126740
+ errorCode: "not_supported",
126741
+ errorMessage: "This operation is not supported."
126742
+ };
126743
+ }
126744
+ if (!config2.jobs?.files?.enabled) {
126745
+ return {
126746
+ success: false,
126747
+ errorCode: "not_supported",
126748
+ errorMessage: "This operation is not supported."
126749
+ };
126750
+ }
126751
+ if (config2.jobs.files.fileExtensions) {
126752
+ if (config2.jobs.files.fileExtensions.every(
126753
+ (ext) => !request.fileName.endsWith(ext)
126754
+ )) {
126755
+ return {
126756
+ success: false,
126757
+ errorCode: "not_supported",
126758
+ errorMessage: "The file extension is not supported."
126759
+ };
126760
+ }
126761
+ }
126762
+ const createdAtMs = Date.now();
126763
+ const scan = await this._jobProvider.scanFile({
126764
+ recordName: request.recordName,
126765
+ fileName: request.fileName,
126766
+ minConfidence: config2.jobs.files.minConfidence
126767
+ });
126768
+ const resultId = v4_default();
126769
+ let bannedLabel = null;
126770
+ for (let label of config2.jobs.files.bannedLabels) {
126771
+ if (label.label) {
126772
+ bannedLabel = scan.labels.find(
126773
+ (l3) => l3.name.localeCompare(label.label, void 0, {
126774
+ sensitivity: "base"
126775
+ }) === 0 && l3.confidence >= label.threshold
126776
+ );
126777
+ }
126778
+ if (bannedLabel) {
126779
+ console.log(
126780
+ `[ModerationController] Banned label (${bannedLabel.name}) detected in file: ${request.fileName}`
126781
+ );
126782
+ if (label.actions.includes("notify") && this._messenger) {
126783
+ await this._messenger.sendRecordNotification({
126784
+ resource: "file",
126785
+ action: "scanned",
126786
+ recordName: request.recordName,
126787
+ resourceId: request.fileName,
126788
+ resultId,
126789
+ labels: scan.labels,
126790
+ timeMs: createdAtMs,
126791
+ bannedLabel,
126792
+ message: `Banned label (${bannedLabel.category ? bannedLabel.category + ":" : ""}${bannedLabel.name ?? ""}) detected in file (${request.recordName}/${request.fileName}).`
126793
+ });
126794
+ }
126795
+ break;
126796
+ }
126797
+ }
126798
+ const result = {
126799
+ id: resultId,
126800
+ recordName: request.recordName,
126801
+ fileName: request.fileName,
126802
+ jobId: request.jobId,
126803
+ labels: scan.labels,
126804
+ modelVersion: scan.modelVersion,
126805
+ createdAtMs,
126806
+ updatedAtMs: Date.now(),
126807
+ appearsToMatchBannedContent: !!bannedLabel
126808
+ };
126809
+ this._store.addFileModerationResult(result);
126810
+ return {
126811
+ success: true,
126812
+ result
126813
+ };
126814
+ } catch (err) {
126815
+ const span = trace.getActiveSpan();
126816
+ span?.recordException(err);
126817
+ span?.setStatus({ code: SpanStatusCode.ERROR });
126818
+ console.error("[ModerationController] Failed to scan file:", err);
126819
+ return {
126820
+ success: false,
126821
+ errorCode: "server_error",
126822
+ errorMessage: "A server error occurred."
126823
+ };
126824
+ }
126825
+ }
126629
126826
  };
126630
126827
  __decorateClass([
126631
126828
  traced(TRACE_NAME16)
126632
126829
  ], ModerationController.prototype, "reportInst", 1);
126830
+ __decorateClass([
126831
+ traced(TRACE_NAME16)
126832
+ ], ModerationController.prototype, "scheduleModerationScans", 1);
126833
+ __decorateClass([
126834
+ traced(TRACE_NAME16)
126835
+ ], ModerationController.prototype, "scanFile", 1);
126836
+
126837
+ // ../aux-records/ModerationConfiguration.ts
126838
+ var moderationSchema = z.object({
126839
+ allowUnauthenticatedReports: z.boolean().describe(
126840
+ "Whether to allow unauthenticated users to report insts. Defaults to true."
126841
+ ).default(true),
126842
+ jobs: z.object({
126843
+ files: z.object({
126844
+ enabled: z.boolean().describe("Whether to enable file moderation."),
126845
+ fileExtensions: z.array(z.string()).describe(
126846
+ "The file extensions to scan. Defaults to common image formats."
126847
+ ).optional().default([".png", ".webp", ".jpg", ".jpeg", ".gif"]),
126848
+ minConfidence: z.number().describe(
126849
+ "The minimum confidence to consider a detected label. Should be between 0 and 1. For AWS Rekognition, this defaults to 0.5."
126850
+ ).min(0).max(1).optional(),
126851
+ bannedLabels: z.array(
126852
+ z.object({
126853
+ label: z.string().describe(
126854
+ "The label that should be matched. If omitted, then labels will be matched by category. See https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html#moderation-api for AWS Rekognition moderation labels."
126855
+ ).optional(),
126856
+ threshold: z.number().describe(
126857
+ "The threshold that the label confidence must equal or exceed in order to be considered a match. Defaults to 0.7."
126858
+ ).min(0).max(1).default(0.7),
126859
+ actions: z.array(z.enum(["notify"])).describe(
126860
+ "The actions that should be taken when a file is detected with the label. Defaults to [notify]."
126861
+ ).optional().default(["notify"])
126862
+ })
126863
+ ).describe(
126864
+ "The labels that should be banned. If a file contains any of these labels, it will be marked as banned. Additionally, a notification will be sent "
126865
+ ).optional().default([
126866
+ {
126867
+ label: "Explicit",
126868
+ threshold: 0.5,
126869
+ actions: ["notify"]
126870
+ },
126871
+ {
126872
+ label: "Non-Explicit Nudity of Intimate parts and Kissing",
126873
+ threshold: 0.5,
126874
+ actions: ["notify"]
126875
+ },
126876
+ {
126877
+ label: "Swimwear or Underwear",
126878
+ threshold: 0.5,
126879
+ actions: ["notify"]
126880
+ },
126881
+ {
126882
+ label: "Violence",
126883
+ threshold: 0.5,
126884
+ actions: ["notify"]
126885
+ },
126886
+ {
126887
+ label: "Visually Disturbing",
126888
+ threshold: 0.5,
126889
+ actions: ["notify"]
126890
+ },
126891
+ {
126892
+ label: "Drugs & Tobacco",
126893
+ threshold: 0.5,
126894
+ actions: ["notify"]
126895
+ },
126896
+ {
126897
+ label: "Alcohol",
126898
+ threshold: 0.5,
126899
+ actions: ["notify"]
126900
+ },
126901
+ {
126902
+ label: "Rude Gestures",
126903
+ threshold: 0.5,
126904
+ actions: ["notify"]
126905
+ },
126906
+ {
126907
+ label: "Gambling",
126908
+ threshold: 0.5,
126909
+ actions: ["notify"]
126910
+ },
126911
+ {
126912
+ label: "Hate Symbols",
126913
+ threshold: 0.5,
126914
+ actions: ["notify"]
126915
+ }
126916
+ ])
126917
+ }).describe("Options for moderating files.")
126918
+ }).describe("The moderation jobs that are enabled.").optional()
126919
+ });
126633
126920
 
126634
126921
  // ../aux-records/NotificationMessenger.ts
126635
126922
  var slackSchema = z.object({
@@ -127562,13 +127849,6 @@ __decorateClass([
127562
127849
  traced(TRACE_NAME17)
127563
127850
  ], LoomController.prototype, "getToken", 1);
127564
127851
 
127565
- // ../aux-records/ModerationConfiguration.ts
127566
- var moderationSchema = z.object({
127567
- allowUnauthenticatedReports: z.boolean().describe(
127568
- "Whether to allow unauthenticated users to report insts. Defaults to true."
127569
- ).default(true)
127570
- });
127571
-
127572
127852
  // ../aux-records/PrivoConfiguration.ts
127573
127853
  var privoSchema = z.object({
127574
127854
  gatewayEndpoint: z.string().describe("The Privo API (aslo called the Gateway) URL.").nonempty(),
@@ -127982,10 +128262,47 @@ var telemetrySchema = z.object({
127982
128262
  "The resource that should be used. See https://opentelemetry.io/docs/specs/semconv/resource/ for more information."
127983
128263
  ).optional().default({})
127984
128264
  });
128265
+ var rekognitionSchema = z.object({
128266
+ moderation: z.object({
128267
+ files: z.object({
128268
+ job: z.object({
128269
+ sourceBucket: z.string().describe(
128270
+ "The bucket that should be scanned when a job is started."
128271
+ ).min(1),
128272
+ reportBucket: z.string().describe(
128273
+ "The bucket that job reports should be placed in."
128274
+ ).min(1),
128275
+ priority: z.number().describe(
128276
+ "The priority of jobs that are created. Higher numbers are higher priority. Defaults to 10."
128277
+ ).int().optional().default(10),
128278
+ roleArn: z.string().describe(
128279
+ "The ARN of the role that should be used to run the job."
128280
+ ).min(1),
128281
+ lambdaFunctionArn: z.string().describe(
128282
+ "The ARN of the lambda function that should be invoked to process the files."
128283
+ ).min(1),
128284
+ tags: z.array(
128285
+ z.object({
128286
+ key: z.string().min(1),
128287
+ value: z.string().min(1)
128288
+ })
128289
+ ).describe("The tags that should be placed on the job.").optional()
128290
+ }).describe("The options specific to starting batch jobs.").optional(),
128291
+ scan: z.object({
128292
+ projectVersionArn: z.string().describe(
128293
+ "The ARN of the custom moderation model that should be used. If omitted, then the default model is used."
128294
+ ).min(1).optional()
128295
+ }).describe("The options specific to scanning files.").optional()
128296
+ })
128297
+ })
128298
+ });
127985
128299
  var serverConfigSchema = z.object({
127986
128300
  s3: s3Schema.describe(
127987
128301
  "S3 Configuration Options. If omitted, then S3 cannot be used for file storage."
127988
128302
  ).optional(),
128303
+ rekognition: rekognitionSchema.describe(
128304
+ "AWS Rekognition configuration options. If omitted, then AWS Rekognition cannot be used for moderation/classification."
128305
+ ).optional(),
127989
128306
  minio: minioSchema.describe(
127990
128307
  "Minio Configuration Options. If omitted, then Minio cannot be used for file storage."
127991
128308
  ).optional(),
@@ -128079,7 +128396,7 @@ var config = new Conf({
128079
128396
  projectName: "casualos-cli"
128080
128397
  });
128081
128398
  var program2 = new Command();
128082
- program2.name("casualos").description("A CLI for CasualOS").version("v3.3.8-alpha.10146812598").option(
128399
+ program2.name("casualos").description("A CLI for CasualOS").version("v3.3.8-alpha.10185283421").option(
128083
128400
  "-e, --endpoint <url>",
128084
128401
  "The endpoint to use for queries. Can be used to override the current endpoint."
128085
128402
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "casualos",
3
- "version": "3.3.8-alpha.10146812598",
3
+ "version": "3.3.8-alpha.10185283421",
4
4
  "description": "Command line interface for CasualOS.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "index.d.ts",
@@ -35,8 +35,8 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@casual-simulation/aux-common": "^3.3.8-alpha.10146812598",
39
- "@casual-simulation/aux-records": "^3.3.8-alpha.10146812598",
38
+ "@casual-simulation/aux-common": "^3.3.8-alpha.10185283421",
39
+ "@casual-simulation/aux-records": "^3.3.8-alpha.10185283421",
40
40
  "axios": "1.6.2",
41
41
  "commander": "12.0.0",
42
42
  "conf": "12.0.0",
@@ -54,5 +54,5 @@
54
54
  "**/*.d.ts",
55
55
  "**/*.def"
56
56
  ],
57
- "gitHead": "fa305e70ffae2a7db952ef49002955d89d58cb46"
57
+ "gitHead": "3ac65fe7f13ca98e64cc50e25e66b0f98a228436"
58
58
  }