easyproctor-hml 2.7.14 → 3.0.0
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.
- package/README.md +6 -0
- package/esm/index.js +303 -150
- package/extension/extensionEasyCatcher.d.ts +11 -0
- package/extension/{extension.d.ts → extensionEasyProctor.d.ts} +1 -1
- package/index.js +303 -150
- package/new-flow/checkers/DeviceCheckerUI.d.ts +11 -0
- package/new-flow/chunk/ChunkStorageService.d.ts +1 -1
- package/new-flow/recorders/CameraRecorder.d.ts +0 -3
- package/package.json +1 -1
- package/proctoring/options/ProctoringOptions.d.ts +1 -0
- package/proctoring/proctoring.d.ts +5 -0
- package/proctoring/useProctoring.d.ts +2 -0
- package/unpkg/easyproctor.min.js +39 -39
package/README.md
CHANGED
|
@@ -263,6 +263,12 @@ const {
|
|
|
263
263
|
token: "...",
|
|
264
264
|
});
|
|
265
265
|
```
|
|
266
|
+
|
|
267
|
+
## Release Note V 3.0.0
|
|
268
|
+
- Envio do vídeo por partes durante o exame para o proctoring REALTIME
|
|
269
|
+
- Fix: correção do bug do import pacote fix-webm-duration
|
|
270
|
+
- Possibilidade de check automático no check devices através do parametro 'auto'
|
|
271
|
+
|
|
266
272
|
## Release Note V 2.7.0
|
|
267
273
|
- Implementação da comunicação com a API para o proctoring do tipo realtime
|
|
268
274
|
- Envio do vídeo durante o exame
|
package/esm/index.js
CHANGED
|
@@ -9340,6 +9340,9 @@ var FaceDetection = class extends BaseDetection {
|
|
|
9340
9340
|
if (this.emmitedFaceAlert) {
|
|
9341
9341
|
this.handleOk("face_stop", "face_detection_on_stream");
|
|
9342
9342
|
}
|
|
9343
|
+
this.numFacesSent = -1;
|
|
9344
|
+
this.emmitedPositionAlert = false;
|
|
9345
|
+
this.emmitedFaceAlert = false;
|
|
9343
9346
|
}
|
|
9344
9347
|
// displayVideoDetections(result: { detections: any; }) {
|
|
9345
9348
|
// // console.log(result);
|
|
@@ -12699,7 +12702,8 @@ var getDefaultProctoringOptions = {
|
|
|
12699
12702
|
useSpyScan: false,
|
|
12700
12703
|
useExternalCamera: false,
|
|
12701
12704
|
useChallenge: false,
|
|
12702
|
-
screenRecorderOptions: { width: 1280, height: 720 }
|
|
12705
|
+
screenRecorderOptions: { width: 1280, height: 720 },
|
|
12706
|
+
auto: false
|
|
12703
12707
|
};
|
|
12704
12708
|
|
|
12705
12709
|
// src/proctoring/options/ProctoringVideoOptions.ts
|
|
@@ -12905,6 +12909,9 @@ function recorder(stream, buffer, onBufferSizeError = false, onBufferSizeErrorCa
|
|
|
12905
12909
|
console.log("stopRecording Recorder n\xE3o est\xE1 em estado recording");
|
|
12906
12910
|
resolve();
|
|
12907
12911
|
}
|
|
12912
|
+
stream.getTracks().forEach((el) => {
|
|
12913
|
+
el.stop();
|
|
12914
|
+
});
|
|
12908
12915
|
});
|
|
12909
12916
|
}
|
|
12910
12917
|
function pauseRecording() {
|
|
@@ -13262,56 +13269,6 @@ var ObjectDetection = class extends BaseDetection {
|
|
|
13262
13269
|
}
|
|
13263
13270
|
};
|
|
13264
13271
|
|
|
13265
|
-
// src/new-flow/recorders/VolumeMeter.ts
|
|
13266
|
-
var VolumeMeter = class {
|
|
13267
|
-
constructor(stream) {
|
|
13268
|
-
this.volume = null;
|
|
13269
|
-
this.animationFrameId = null;
|
|
13270
|
-
this.stream = stream;
|
|
13271
|
-
}
|
|
13272
|
-
async start(options = {}) {
|
|
13273
|
-
return new Promise((resolve, reject) => {
|
|
13274
|
-
try {
|
|
13275
|
-
this.audioContext = new AudioContext();
|
|
13276
|
-
this.analyser = this.audioContext.createAnalyser();
|
|
13277
|
-
this.microphone = this.audioContext.createMediaStreamSource(this.stream);
|
|
13278
|
-
this.analyser.smoothingTimeConstant = 0.8;
|
|
13279
|
-
this.analyser.fftSize = 1024;
|
|
13280
|
-
this.microphone.connect(this.analyser);
|
|
13281
|
-
const processAudio = () => {
|
|
13282
|
-
const array = new Uint8Array(this.analyser.frequencyBinCount);
|
|
13283
|
-
this.analyser.getByteFrequencyData(array);
|
|
13284
|
-
const arraySum = array.reduce((a3, value) => a3 + value, 0);
|
|
13285
|
-
const average = arraySum / array.length;
|
|
13286
|
-
this.setVolume(average);
|
|
13287
|
-
options.setVolume && options.setVolume(average);
|
|
13288
|
-
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
13289
|
-
};
|
|
13290
|
-
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
13291
|
-
resolve(true);
|
|
13292
|
-
} catch (error) {
|
|
13293
|
-
this.stop();
|
|
13294
|
-
reject(`Error: ${error}`);
|
|
13295
|
-
}
|
|
13296
|
-
});
|
|
13297
|
-
}
|
|
13298
|
-
stop() {
|
|
13299
|
-
var _a2, _b, _c2;
|
|
13300
|
-
if (this.animationFrameId !== null) {
|
|
13301
|
-
cancelAnimationFrame(this.animationFrameId);
|
|
13302
|
-
}
|
|
13303
|
-
(_a2 = this.audioContext) == null ? void 0 : _a2.close();
|
|
13304
|
-
(_b = this.microphone) == null ? void 0 : _b.disconnect();
|
|
13305
|
-
(_c2 = this.analyser) == null ? void 0 : _c2.disconnect();
|
|
13306
|
-
}
|
|
13307
|
-
getVolume() {
|
|
13308
|
-
return this.volume;
|
|
13309
|
-
}
|
|
13310
|
-
setVolume(value) {
|
|
13311
|
-
this.volume = value;
|
|
13312
|
-
}
|
|
13313
|
-
};
|
|
13314
|
-
|
|
13315
13272
|
// src/new-flow/chunk/ChunkStorageService.ts
|
|
13316
13273
|
var _ChunkStorageService = class _ChunkStorageService {
|
|
13317
13274
|
constructor() {
|
|
@@ -13328,13 +13285,7 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
13328
13285
|
_ChunkStorageService.DB_VERSION
|
|
13329
13286
|
);
|
|
13330
13287
|
request.onerror = () => {
|
|
13331
|
-
|
|
13332
|
-
console.error("IndexedDB error:", request.error);
|
|
13333
|
-
reject(
|
|
13334
|
-
new Error(
|
|
13335
|
-
`N\xE3o foi poss\xEDvel conectar ao IndexedDB para chunks: ${(_a2 = request.error) == null ? void 0 : _a2.name} - ${(_b = request.error) == null ? void 0 : _b.message}`
|
|
13336
|
-
)
|
|
13337
|
-
);
|
|
13288
|
+
reject(new Error("N\xE3o foi poss\xEDvel conectar ao IndexedDB para chunks."));
|
|
13338
13289
|
};
|
|
13339
13290
|
request.onupgradeneeded = () => {
|
|
13340
13291
|
const db = request.result;
|
|
@@ -13557,8 +13508,8 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
13557
13508
|
}
|
|
13558
13509
|
};
|
|
13559
13510
|
_ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
|
|
13560
|
-
/**
|
|
13561
|
-
_ChunkStorageService.DB_VERSION =
|
|
13511
|
+
/** v2: índices uploaded numéricos; v3: campo arrayBuffer em vez de blob */
|
|
13512
|
+
_ChunkStorageService.DB_VERSION = 3;
|
|
13562
13513
|
_ChunkStorageService.STORE_NAME = "chunks";
|
|
13563
13514
|
var ChunkStorageService = _ChunkStorageService;
|
|
13564
13515
|
|
|
@@ -13741,8 +13692,9 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13741
13692
|
let virtualStart = this.totalBytesPurged;
|
|
13742
13693
|
const chunksWithMeta = allChunks.map((c3) => {
|
|
13743
13694
|
const start = virtualStart;
|
|
13744
|
-
const
|
|
13745
|
-
|
|
13695
|
+
const byteLength = c3.arrayBuffer.byteLength;
|
|
13696
|
+
const end = start + byteLength - 1;
|
|
13697
|
+
virtualStart += byteLength;
|
|
13746
13698
|
return { chunk: c3, start, end };
|
|
13747
13699
|
});
|
|
13748
13700
|
let combinedBlobParts = [];
|
|
@@ -13752,8 +13704,8 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13752
13704
|
for (const meta of chunksWithMeta) {
|
|
13753
13705
|
if (this.currentOffset > meta.end) continue;
|
|
13754
13706
|
const sliceStart = Math.max(0, this.currentOffset - meta.start);
|
|
13755
|
-
const
|
|
13756
|
-
combinedBlobParts.push(
|
|
13707
|
+
const sliceBuf = meta.chunk.arrayBuffer.slice(sliceStart);
|
|
13708
|
+
combinedBlobParts.push(new Blob([sliceBuf]));
|
|
13757
13709
|
lastProcessedChunkId = meta.chunk.id;
|
|
13758
13710
|
finalChunkIndex = meta.chunk.chunkIndex;
|
|
13759
13711
|
}
|
|
@@ -13787,7 +13739,10 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13787
13739
|
}
|
|
13788
13740
|
if (this.config.cleanAfterUpload) {
|
|
13789
13741
|
const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
|
|
13790
|
-
const sizePurged = chunksToClear.reduce(
|
|
13742
|
+
const sizePurged = chunksToClear.reduce(
|
|
13743
|
+
(acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
|
|
13744
|
+
0
|
|
13745
|
+
);
|
|
13791
13746
|
await this.chunkStorage.clearUploadedChunks(this.proctoringId);
|
|
13792
13747
|
if (sizePurged > 0) {
|
|
13793
13748
|
this.totalBytesPurged += sizePurged;
|
|
@@ -13991,7 +13946,6 @@ var _CameraRecorder = class _CameraRecorder {
|
|
|
13991
13946
|
this.currentRetries = 0;
|
|
13992
13947
|
this.packageCount = 0;
|
|
13993
13948
|
this.failedUploads = 0;
|
|
13994
|
-
this.noiseWait = 20;
|
|
13995
13949
|
this.options = options;
|
|
13996
13950
|
this.videoOptions = videoOptions;
|
|
13997
13951
|
this.backend = backend;
|
|
@@ -14413,10 +14367,11 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14413
14367
|
const savePromise = (async () => {
|
|
14414
14368
|
var _a2;
|
|
14415
14369
|
try {
|
|
14370
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
14416
14371
|
await this.chunkStorage.saveChunk({
|
|
14417
14372
|
proctoringId: this.proctoringId,
|
|
14418
14373
|
chunkIndex: this.chunkIndex,
|
|
14419
|
-
|
|
14374
|
+
arrayBuffer,
|
|
14420
14375
|
timestamp: Date.now(),
|
|
14421
14376
|
uploaded: 0,
|
|
14422
14377
|
mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
|
|
@@ -14571,35 +14526,36 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14571
14526
|
const settings = this.cameraStream.getVideoTracks()[0].getSettings();
|
|
14572
14527
|
const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
|
|
14573
14528
|
if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
|
|
14529
|
+
let isUploaded = false;
|
|
14574
14530
|
if (this.isChunkEnabled) {
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
const objectName = `${this.proctoringId}/${fileName}`;
|
|
14581
|
-
const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
|
|
14582
|
-
if (isUploaded) {
|
|
14583
|
-
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
14584
|
-
return;
|
|
14585
|
-
}
|
|
14586
|
-
}
|
|
14531
|
+
if (this.backend && this.backendToken && this.proctoringId) {
|
|
14532
|
+
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
14533
|
+
const objectName = `${this.proctoringId}/${fileName}`;
|
|
14534
|
+
isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
|
|
14535
|
+
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
14587
14536
|
}
|
|
14588
14537
|
}
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14538
|
+
if (!isUploaded) {
|
|
14539
|
+
const rawBlob = new Blob(this.blobs, {
|
|
14540
|
+
type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
|
|
14541
|
+
});
|
|
14542
|
+
let finalBlob = rawBlob;
|
|
14543
|
+
if (typeof fixWebmDuration === "function") {
|
|
14544
|
+
finalBlob = await fixWebmDuration(rawBlob, this.duration);
|
|
14545
|
+
} else {
|
|
14546
|
+
console.warn("fixWebmDuration n\xE3o dispon\xEDvel");
|
|
14547
|
+
}
|
|
14548
|
+
session.addRecording({
|
|
14549
|
+
device: `Audio
|
|
14595
14550
|
Sample Rate: ${settingsAudio.sampleRate}
|
|
14596
14551
|
Sample Size: ${settingsAudio.sampleSize}
|
|
14597
14552
|
|
|
14598
14553
|
Video:
|
|
14599
14554
|
${JSON.stringify(this.recorderOptions)}`,
|
|
14600
|
-
|
|
14601
|
-
|
|
14602
|
-
|
|
14555
|
+
arrayBuffer: await finalBlob.arrayBuffer(),
|
|
14556
|
+
origin: "Camera" /* Camera */
|
|
14557
|
+
});
|
|
14558
|
+
}
|
|
14603
14559
|
}
|
|
14604
14560
|
}
|
|
14605
14561
|
async getFile(file, name, type) {
|
|
@@ -14612,51 +14568,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14612
14568
|
});
|
|
14613
14569
|
});
|
|
14614
14570
|
}
|
|
14615
|
-
/**
|
|
14616
|
-
* Verifica se a internet está estável para realizar o upload do vídeo na íntegra.
|
|
14617
|
-
*/
|
|
14618
|
-
async checkInternetStability() {
|
|
14619
|
-
var _a2;
|
|
14620
|
-
if (!navigator.onLine) return false;
|
|
14621
|
-
try {
|
|
14622
|
-
const controller = new AbortController();
|
|
14623
|
-
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
14624
|
-
const baseUrl = (_a2 = this.backend) == null ? void 0 : _a2.getBaseUrl();
|
|
14625
|
-
if (!baseUrl) return true;
|
|
14626
|
-
const response = await fetch(`${baseUrl}/Client/health`, {
|
|
14627
|
-
method: "GET",
|
|
14628
|
-
signal: controller.signal
|
|
14629
|
-
});
|
|
14630
|
-
clearTimeout(timeoutId);
|
|
14631
|
-
return response.status < 500;
|
|
14632
|
-
} catch (e3) {
|
|
14633
|
-
console.warn("[CameraRecorder] Internet inst\xE1vel ou lenta detectada para upload integral.");
|
|
14634
|
-
return false;
|
|
14635
|
-
}
|
|
14636
|
-
}
|
|
14637
|
-
onNoiseDetected() {
|
|
14638
|
-
var _a2, _b, _c2;
|
|
14639
|
-
if (this.options.proctoringType === "REALTIME") return;
|
|
14640
|
-
if (!this.volumeMeter && this.cameraStream) {
|
|
14641
|
-
this.volumeMeter = new VolumeMeter(this.cameraStream);
|
|
14642
|
-
this.volumeMeter.start().catch((e3) => {
|
|
14643
|
-
console.log(e3);
|
|
14644
|
-
this.volumeMeter = void 0;
|
|
14645
|
-
});
|
|
14646
|
-
}
|
|
14647
|
-
const volume = (_b = (_a2 = this.volumeMeter) == null ? void 0 : _a2.getVolume()) != null ? _b : 0;
|
|
14648
|
-
if (volume >= (((_c2 = this.paramsConfig.audioBehaviourParameters) == null ? void 0 : _c2.noiseLimit) || 40)) {
|
|
14649
|
-
if (this.noiseWait >= 20) {
|
|
14650
|
-
this.options.onRealtimeAlertsCallback({
|
|
14651
|
-
status: "ALERT",
|
|
14652
|
-
description: "Barulho detectado",
|
|
14653
|
-
type: "audio_detection_on_stream"
|
|
14654
|
-
});
|
|
14655
|
-
this.noiseWait = 0;
|
|
14656
|
-
}
|
|
14657
|
-
}
|
|
14658
|
-
this.noiseWait++;
|
|
14659
|
-
}
|
|
14660
14571
|
};
|
|
14661
14572
|
// ========================
|
|
14662
14573
|
// Chunk & Lifecycle
|
|
@@ -14667,10 +14578,62 @@ _CameraRecorder.CHUNK_TIMESLICE_MS = 6e4;
|
|
|
14667
14578
|
_CameraRecorder.LS_SESSION_KEY = "ep_proctoring_session";
|
|
14668
14579
|
var CameraRecorder = _CameraRecorder;
|
|
14669
14580
|
|
|
14581
|
+
// src/new-flow/recorders/VolumeMeter.ts
|
|
14582
|
+
var VolumeMeter = class {
|
|
14583
|
+
constructor(stream) {
|
|
14584
|
+
this.volume = null;
|
|
14585
|
+
this.animationFrameId = null;
|
|
14586
|
+
this.stream = stream;
|
|
14587
|
+
}
|
|
14588
|
+
async start(options = {}) {
|
|
14589
|
+
return new Promise((resolve, reject) => {
|
|
14590
|
+
try {
|
|
14591
|
+
this.audioContext = new AudioContext();
|
|
14592
|
+
this.analyser = this.audioContext.createAnalyser();
|
|
14593
|
+
this.microphone = this.audioContext.createMediaStreamSource(this.stream);
|
|
14594
|
+
this.analyser.smoothingTimeConstant = 0.8;
|
|
14595
|
+
this.analyser.fftSize = 1024;
|
|
14596
|
+
this.microphone.connect(this.analyser);
|
|
14597
|
+
const processAudio = () => {
|
|
14598
|
+
const array = new Uint8Array(this.analyser.frequencyBinCount);
|
|
14599
|
+
this.analyser.getByteFrequencyData(array);
|
|
14600
|
+
const arraySum = array.reduce((a3, value) => a3 + value, 0);
|
|
14601
|
+
const average = arraySum / array.length;
|
|
14602
|
+
this.setVolume(average);
|
|
14603
|
+
options.setVolume && options.setVolume(average);
|
|
14604
|
+
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
14605
|
+
};
|
|
14606
|
+
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
14607
|
+
resolve(true);
|
|
14608
|
+
} catch (error) {
|
|
14609
|
+
this.stop();
|
|
14610
|
+
reject(`Error: ${error}`);
|
|
14611
|
+
}
|
|
14612
|
+
});
|
|
14613
|
+
}
|
|
14614
|
+
stop() {
|
|
14615
|
+
var _a2, _b, _c2;
|
|
14616
|
+
if (this.animationFrameId !== null) {
|
|
14617
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
14618
|
+
}
|
|
14619
|
+
(_a2 = this.audioContext) == null ? void 0 : _a2.close();
|
|
14620
|
+
(_b = this.microphone) == null ? void 0 : _b.disconnect();
|
|
14621
|
+
(_c2 = this.analyser) == null ? void 0 : _c2.disconnect();
|
|
14622
|
+
}
|
|
14623
|
+
getVolume() {
|
|
14624
|
+
return this.volume;
|
|
14625
|
+
}
|
|
14626
|
+
setVolume(value) {
|
|
14627
|
+
this.volume = value;
|
|
14628
|
+
}
|
|
14629
|
+
};
|
|
14630
|
+
|
|
14670
14631
|
// src/new-flow/checkers/DeviceCheckerUI.ts
|
|
14671
14632
|
var DeviceCheckerUI = class {
|
|
14672
14633
|
constructor(options = getDefaultProctoringOptions, _videoOptions) {
|
|
14673
14634
|
this.videoOptions = { width: 1080, height: 720, minWidth: 0, minHeight: 0 };
|
|
14635
|
+
this.autoConfirmTimer = null;
|
|
14636
|
+
this.autoConfirmSeconds = 5;
|
|
14674
14637
|
this.options = {
|
|
14675
14638
|
...getDefaultProctoringOptions,
|
|
14676
14639
|
...options,
|
|
@@ -15436,9 +15399,53 @@ var DeviceCheckerUI = class {
|
|
|
15436
15399
|
}));
|
|
15437
15400
|
}
|
|
15438
15401
|
closeModal() {
|
|
15402
|
+
this.stopAutoConfirm();
|
|
15439
15403
|
const checkDevices = document.querySelector("#checkDevices");
|
|
15440
15404
|
checkDevices == null ? void 0 : checkDevices.remove();
|
|
15441
15405
|
}
|
|
15406
|
+
verifyAutoConfirm(status) {
|
|
15407
|
+
var _a2;
|
|
15408
|
+
if (!((_a2 = this.options) == null ? void 0 : _a2.auto)) return;
|
|
15409
|
+
let isAllGreen = status.allowedResolution && status.allowedPositionFace && status.allowedAmbient && status.allowedMicrophone;
|
|
15410
|
+
if (this.options.useSpyScan) {
|
|
15411
|
+
isAllGreen = isAllGreen && status.allowedSpyScan === true;
|
|
15412
|
+
}
|
|
15413
|
+
if (isAllGreen) {
|
|
15414
|
+
if (!this.autoConfirmTimer) {
|
|
15415
|
+
this.startAutoConfirm();
|
|
15416
|
+
}
|
|
15417
|
+
} else {
|
|
15418
|
+
if (this.autoConfirmTimer) {
|
|
15419
|
+
this.stopAutoConfirm();
|
|
15420
|
+
}
|
|
15421
|
+
}
|
|
15422
|
+
}
|
|
15423
|
+
startAutoConfirm() {
|
|
15424
|
+
this.autoConfirmSeconds = 5;
|
|
15425
|
+
const btn = document.getElementById("confirmBtn");
|
|
15426
|
+
if (btn && !btn.disabled) {
|
|
15427
|
+
btn.innerText = `Continuando em ${this.autoConfirmSeconds}s...`;
|
|
15428
|
+
this.autoConfirmTimer = setInterval(() => {
|
|
15429
|
+
this.autoConfirmSeconds--;
|
|
15430
|
+
if (this.autoConfirmSeconds <= 0) {
|
|
15431
|
+
this.stopAutoConfirm();
|
|
15432
|
+
btn.click();
|
|
15433
|
+
} else {
|
|
15434
|
+
btn.innerText = `Continuando em ${this.autoConfirmSeconds}s...`;
|
|
15435
|
+
}
|
|
15436
|
+
}, 1e3);
|
|
15437
|
+
}
|
|
15438
|
+
}
|
|
15439
|
+
stopAutoConfirm() {
|
|
15440
|
+
if (this.autoConfirmTimer) {
|
|
15441
|
+
clearInterval(this.autoConfirmTimer);
|
|
15442
|
+
this.autoConfirmTimer = null;
|
|
15443
|
+
}
|
|
15444
|
+
const btn = document.getElementById("confirmBtn");
|
|
15445
|
+
if (btn) {
|
|
15446
|
+
btn.innerText = "Continuar";
|
|
15447
|
+
}
|
|
15448
|
+
}
|
|
15442
15449
|
modalActions(closeCheckDevices) {
|
|
15443
15450
|
const cancelBtn = document.getElementById("cancelBtn");
|
|
15444
15451
|
const confirmBtn = document.getElementById("confirmBtn");
|
|
@@ -15805,6 +15812,7 @@ var _DeviceCheckerService = class _DeviceCheckerService {
|
|
|
15805
15812
|
}
|
|
15806
15813
|
}
|
|
15807
15814
|
onUpdateCallback() {
|
|
15815
|
+
var _a2;
|
|
15808
15816
|
if (typeof this.onUpdateCb === "function") {
|
|
15809
15817
|
this.onUpdateCb({
|
|
15810
15818
|
allowedResolution: this.allowedResolution,
|
|
@@ -15815,6 +15823,15 @@ var _DeviceCheckerService = class _DeviceCheckerService {
|
|
|
15815
15823
|
faceDetectionAlerts: this.faceDetectionAlerts
|
|
15816
15824
|
});
|
|
15817
15825
|
}
|
|
15826
|
+
if (((_a2 = this.options) == null ? void 0 : _a2.auto) && this.DeviceCheckerUI) {
|
|
15827
|
+
this.DeviceCheckerUI.verifyAutoConfirm({
|
|
15828
|
+
allowedResolution: this.allowedResolution,
|
|
15829
|
+
allowedPositionFace: this.allowedPositionFace,
|
|
15830
|
+
allowedAmbient: this.allowedAmbient,
|
|
15831
|
+
allowedMicrophone: this.allowedMicrophone,
|
|
15832
|
+
allowedSpyScan: this.allowedSpyScan
|
|
15833
|
+
});
|
|
15834
|
+
}
|
|
15818
15835
|
}
|
|
15819
15836
|
async checkDevices(options = getDefaultProctoringOptions, _videoOptions = getDefaultProctoringVideoOptions) {
|
|
15820
15837
|
var _a2;
|
|
@@ -16021,16 +16038,19 @@ var _DeviceCheckerService = class _DeviceCheckerService {
|
|
|
16021
16038
|
}).finally(() => {
|
|
16022
16039
|
this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
|
|
16023
16040
|
this.DeviceCheckerUI && this.allowedSpyScan != null && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
|
|
16041
|
+
this.onUpdateCallback();
|
|
16024
16042
|
});
|
|
16025
16043
|
} else {
|
|
16026
16044
|
this.allowedSpyScan = false;
|
|
16027
16045
|
this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
|
|
16028
16046
|
this.DeviceCheckerUI && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
|
|
16047
|
+
this.onUpdateCallback();
|
|
16029
16048
|
}
|
|
16030
16049
|
} catch (error) {
|
|
16031
16050
|
this.allowedSpyScan = false;
|
|
16032
16051
|
this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
|
|
16033
16052
|
this.DeviceCheckerUI && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
|
|
16053
|
+
this.onUpdateCallback();
|
|
16034
16054
|
console.log(error);
|
|
16035
16055
|
}
|
|
16036
16056
|
}
|
|
@@ -16350,8 +16370,8 @@ var CapturePhoto = class {
|
|
|
16350
16370
|
}
|
|
16351
16371
|
};
|
|
16352
16372
|
|
|
16353
|
-
// src/extension/
|
|
16354
|
-
var
|
|
16373
|
+
// src/extension/extensionEasyProctor.ts
|
|
16374
|
+
var ExtensionEasyProctor = class {
|
|
16355
16375
|
constructor() {
|
|
16356
16376
|
this.hasExtension = false;
|
|
16357
16377
|
this.tryes = 0;
|
|
@@ -16396,6 +16416,89 @@ var Extension = class {
|
|
|
16396
16416
|
}
|
|
16397
16417
|
};
|
|
16398
16418
|
|
|
16419
|
+
// src/extension/extensionEasyCatcher.ts
|
|
16420
|
+
var ExtensionEasyCatcher = class {
|
|
16421
|
+
constructor(options) {
|
|
16422
|
+
this.hasExtension = false;
|
|
16423
|
+
this.tryes = 0;
|
|
16424
|
+
this.responseStart = false;
|
|
16425
|
+
this.options = options || {};
|
|
16426
|
+
}
|
|
16427
|
+
/**
|
|
16428
|
+
* Verifica se a extensão está instalada e ativa.
|
|
16429
|
+
* Retorna o número da versão se encontrada, ou lança erro após timeout.
|
|
16430
|
+
*/
|
|
16431
|
+
checkExtensionInstalled(timeoutMs = 2e3) {
|
|
16432
|
+
return new Promise((resolve, reject) => {
|
|
16433
|
+
let handled = false;
|
|
16434
|
+
const handler = (event) => {
|
|
16435
|
+
if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "version") {
|
|
16436
|
+
handled = true;
|
|
16437
|
+
window.removeEventListener("message", handler);
|
|
16438
|
+
resolve(event.data.message);
|
|
16439
|
+
}
|
|
16440
|
+
};
|
|
16441
|
+
window.addEventListener("message", handler);
|
|
16442
|
+
window.postMessage({
|
|
16443
|
+
type: "easycatcher",
|
|
16444
|
+
func: "verifyExtensionEasycatcher"
|
|
16445
|
+
}, "*");
|
|
16446
|
+
setTimeout(() => {
|
|
16447
|
+
if (!handled) {
|
|
16448
|
+
window.removeEventListener("message", handler);
|
|
16449
|
+
reject(new Error("Extens\xE3o n\xE3o detectada ou n\xE3o respondeu."));
|
|
16450
|
+
}
|
|
16451
|
+
}, timeoutMs);
|
|
16452
|
+
});
|
|
16453
|
+
}
|
|
16454
|
+
/**
|
|
16455
|
+
* Solicita o JSON da sessão atual capturado pela extensão.
|
|
16456
|
+
*/
|
|
16457
|
+
getSessionData(timeoutMs = 5e3) {
|
|
16458
|
+
return new Promise((resolve, reject) => {
|
|
16459
|
+
let handled = false;
|
|
16460
|
+
const handler = (event) => {
|
|
16461
|
+
if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "data_response") {
|
|
16462
|
+
handled = true;
|
|
16463
|
+
window.removeEventListener("message", handler);
|
|
16464
|
+
resolve(event.data.payload);
|
|
16465
|
+
}
|
|
16466
|
+
};
|
|
16467
|
+
window.addEventListener("message", handler);
|
|
16468
|
+
window.postMessage({
|
|
16469
|
+
type: "easycatcher",
|
|
16470
|
+
func: "getDataExtensionEasycatcher"
|
|
16471
|
+
}, "*");
|
|
16472
|
+
setTimeout(() => {
|
|
16473
|
+
if (!handled) {
|
|
16474
|
+
window.removeEventListener("message", handler);
|
|
16475
|
+
reject(new Error("Timeout ao aguardar dados da extens\xE3o."));
|
|
16476
|
+
}
|
|
16477
|
+
}, timeoutMs);
|
|
16478
|
+
});
|
|
16479
|
+
}
|
|
16480
|
+
start() {
|
|
16481
|
+
return new Promise((resolve, reject) => {
|
|
16482
|
+
let handled = false;
|
|
16483
|
+
const handler = (event) => {
|
|
16484
|
+
if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "started_confirmed") {
|
|
16485
|
+
handled = true;
|
|
16486
|
+
window.removeEventListener("message", handler);
|
|
16487
|
+
resolve(true);
|
|
16488
|
+
}
|
|
16489
|
+
};
|
|
16490
|
+
window.addEventListener("message", handler);
|
|
16491
|
+
window.postMessage({ type: "easycatcher", func: "startExtensionEasycatcher" }, "*");
|
|
16492
|
+
setTimeout(() => {
|
|
16493
|
+
if (!handled) {
|
|
16494
|
+
window.removeEventListener("message", handler);
|
|
16495
|
+
reject(new Error("Timeout: Extens\xE3o n\xE3o confirmou o in\xEDcio."));
|
|
16496
|
+
}
|
|
16497
|
+
}, 3e3);
|
|
16498
|
+
});
|
|
16499
|
+
}
|
|
16500
|
+
};
|
|
16501
|
+
|
|
16399
16502
|
// src/modules/onChangeDevices.ts
|
|
16400
16503
|
var onChangeDevices = class {
|
|
16401
16504
|
constructor(repositoryDevices, proctoringId2, sessionOptions, allRecorders) {
|
|
@@ -23571,7 +23674,10 @@ var Proctoring = class {
|
|
|
23571
23674
|
if (this.context.token === void 0) {
|
|
23572
23675
|
throw TOKEN_MISSING;
|
|
23573
23676
|
}
|
|
23574
|
-
|
|
23677
|
+
if (options.useChallenge) {
|
|
23678
|
+
this.extensionEasycatcher = new ExtensionEasyCatcher();
|
|
23679
|
+
}
|
|
23680
|
+
this.extension = new ExtensionEasyProctor();
|
|
23575
23681
|
this.extension.addEventListener();
|
|
23576
23682
|
const baseURL = this.backend.selectBaseUrl(this.context.type);
|
|
23577
23683
|
const devices = await enumarateDevices();
|
|
@@ -23639,20 +23745,6 @@ var Proctoring = class {
|
|
|
23639
23745
|
} catch (error) {
|
|
23640
23746
|
throw SAFE_BROWSER_API_NOT_FOUND;
|
|
23641
23747
|
}
|
|
23642
|
-
this.allRecorders.cameraRecorder.onVisibilityRestored = () => {
|
|
23643
|
-
console.log("[Proctoring] Usu\xE1rio retornou ao browser.");
|
|
23644
|
-
this.onVisibilityRestoredCallback();
|
|
23645
|
-
};
|
|
23646
|
-
if (this.sessionOptions.proctoringType === "REALTIME" && !isSafeBrowser()) {
|
|
23647
|
-
try {
|
|
23648
|
-
await BackgroundUploadService.recoverPendingUploads(
|
|
23649
|
-
this.backend,
|
|
23650
|
-
this.context.token
|
|
23651
|
-
);
|
|
23652
|
-
} catch (e3) {
|
|
23653
|
-
console.warn("[Proctoring] Erro ao recuperar chunks de sess\xE3o anterior:", e3);
|
|
23654
|
-
}
|
|
23655
|
-
}
|
|
23656
23748
|
try {
|
|
23657
23749
|
console.log("Starting recorders");
|
|
23658
23750
|
await this.recorder.startAll();
|
|
@@ -23733,7 +23825,9 @@ Error: ${error}`
|
|
|
23733
23825
|
this.appChecker && await this.appChecker.disconnectWebSocket();
|
|
23734
23826
|
await this.recorder.saveAllOnSession();
|
|
23735
23827
|
await this.sendPendingRealtimeAlerts();
|
|
23828
|
+
trackers.registerError(this.proctoringId, `finish this.repository.save starting`);
|
|
23736
23829
|
await this.repository.save(this.proctoringSession);
|
|
23830
|
+
trackers.registerError(this.proctoringId, `finish this.repository.save finished`);
|
|
23737
23831
|
let uploader;
|
|
23738
23832
|
let uploaderServices;
|
|
23739
23833
|
if (versionVerify() !== "1.0.0.0") {
|
|
@@ -23955,6 +24049,61 @@ Error: ` + error
|
|
|
23955
24049
|
_screenStream: (_a2 = this.allRecorders.screenRecorder) == null ? void 0 : _a2.screenStream
|
|
23956
24050
|
};
|
|
23957
24051
|
}
|
|
24052
|
+
async startChallenge(templateId) {
|
|
24053
|
+
var _a2;
|
|
24054
|
+
if (!this.sessionOptions.useChallenge) {
|
|
24055
|
+
throw new Error("useChallenge is set as false on start method");
|
|
24056
|
+
}
|
|
24057
|
+
await this.extensionEasycatcher.checkExtensionInstalled().catch((err) => {
|
|
24058
|
+
throw new Error("EasyCatcher Extension is not installed");
|
|
24059
|
+
});
|
|
24060
|
+
this.extensionEasycatcher.start();
|
|
24061
|
+
const start = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
|
|
24062
|
+
await this.backend.startChallenge({
|
|
24063
|
+
proctoringId: this.proctoringId,
|
|
24064
|
+
templateId,
|
|
24065
|
+
start
|
|
24066
|
+
}).then((resp) => {
|
|
24067
|
+
console.log(resp);
|
|
24068
|
+
this.challengeId = resp.id;
|
|
24069
|
+
}).catch((reason) => {
|
|
24070
|
+
trackers.registerError(
|
|
24071
|
+
this.proctoringId,
|
|
24072
|
+
"N\xE3o foi poss\xEDvel iniciar desafio!"
|
|
24073
|
+
);
|
|
24074
|
+
throw reason;
|
|
24075
|
+
});
|
|
24076
|
+
this.isChallengeRunning = true;
|
|
24077
|
+
}
|
|
24078
|
+
async stopChallenge() {
|
|
24079
|
+
var _a2;
|
|
24080
|
+
if (!this.isChallengeRunning) {
|
|
24081
|
+
throw new Error("Challenge not started");
|
|
24082
|
+
}
|
|
24083
|
+
try {
|
|
24084
|
+
const sessionData = await this.extensionEasycatcher.getSessionData();
|
|
24085
|
+
const end = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
|
|
24086
|
+
await this.backend.stopChallenge(
|
|
24087
|
+
this.challengeId,
|
|
24088
|
+
{
|
|
24089
|
+
end,
|
|
24090
|
+
data: sessionData
|
|
24091
|
+
}
|
|
24092
|
+
).catch((reason) => {
|
|
24093
|
+
trackers.registerError(
|
|
24094
|
+
this.proctoringId,
|
|
24095
|
+
"N\xE3o foi poss\xEDvel finalizar o desafio no backend!"
|
|
24096
|
+
);
|
|
24097
|
+
return void 0;
|
|
24098
|
+
});
|
|
24099
|
+
this.isChallengeRunning = false;
|
|
24100
|
+
} catch (error) {
|
|
24101
|
+
trackers.registerError(
|
|
24102
|
+
this.proctoringId,
|
|
24103
|
+
"Erro ao recuperar dados da extens\xE3o: " + error.message
|
|
24104
|
+
);
|
|
24105
|
+
}
|
|
24106
|
+
}
|
|
23958
24107
|
};
|
|
23959
24108
|
|
|
23960
24109
|
// src/proctoring/SignTerm.ts
|
|
@@ -24183,6 +24332,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
|
|
|
24183
24332
|
return originalStart(parameters2, videoOptions);
|
|
24184
24333
|
};
|
|
24185
24334
|
const finish = proctoring.finish.bind(proctoring);
|
|
24335
|
+
const startChallenge = proctoring.startChallenge.bind(proctoring);
|
|
24336
|
+
const stopChallenge = proctoring.stopChallenge.bind(proctoring);
|
|
24186
24337
|
const pause = proctoring.pause.bind(proctoring);
|
|
24187
24338
|
const resume = proctoring.resume.bind(proctoring);
|
|
24188
24339
|
const onFocus = proctoring.setOnFocusCallback.bind(proctoring);
|
|
@@ -24207,6 +24358,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
|
|
|
24207
24358
|
login,
|
|
24208
24359
|
start,
|
|
24209
24360
|
finish,
|
|
24361
|
+
startChallenge,
|
|
24362
|
+
stopChallenge,
|
|
24210
24363
|
onFocus,
|
|
24211
24364
|
onLostFocus,
|
|
24212
24365
|
onChangeDevices: onChangeDevices2,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ProctoringFinisherOptions } from "../proctoring/proctoring";
|
|
2
|
+
export declare class ExtensionEasyCatcher {
|
|
3
|
+
hasExtension: boolean;
|
|
4
|
+
tryes: number;
|
|
5
|
+
responseStart: boolean;
|
|
6
|
+
options: ProctoringFinisherOptions;
|
|
7
|
+
constructor(options?: ProctoringFinisherOptions);
|
|
8
|
+
checkExtensionInstalled(timeoutMs?: number): Promise<string>;
|
|
9
|
+
getSessionData(timeoutMs?: number): Promise<any>;
|
|
10
|
+
start(): Promise<boolean>;
|
|
11
|
+
}
|