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/index.js
CHANGED
|
@@ -26625,6 +26625,9 @@ var FaceDetection = class extends BaseDetection {
|
|
|
26625
26625
|
if (this.emmitedFaceAlert) {
|
|
26626
26626
|
this.handleOk("face_stop", "face_detection_on_stream");
|
|
26627
26627
|
}
|
|
26628
|
+
this.numFacesSent = -1;
|
|
26629
|
+
this.emmitedPositionAlert = false;
|
|
26630
|
+
this.emmitedFaceAlert = false;
|
|
26628
26631
|
}
|
|
26629
26632
|
// displayVideoDetections(result: { detections: any; }) {
|
|
26630
26633
|
// // console.log(result);
|
|
@@ -30796,7 +30799,8 @@ var getDefaultProctoringOptions = {
|
|
|
30796
30799
|
useSpyScan: false,
|
|
30797
30800
|
useExternalCamera: false,
|
|
30798
30801
|
useChallenge: false,
|
|
30799
|
-
screenRecorderOptions: { width: 1280, height: 720 }
|
|
30802
|
+
screenRecorderOptions: { width: 1280, height: 720 },
|
|
30803
|
+
auto: false
|
|
30800
30804
|
};
|
|
30801
30805
|
|
|
30802
30806
|
// src/proctoring/options/ProctoringVideoOptions.ts
|
|
@@ -31002,6 +31006,9 @@ function recorder(stream4, buffer, onBufferSizeError = false, onBufferSizeErrorC
|
|
|
31002
31006
|
console.log("stopRecording Recorder n\xE3o est\xE1 em estado recording");
|
|
31003
31007
|
resolve();
|
|
31004
31008
|
}
|
|
31009
|
+
stream4.getTracks().forEach((el) => {
|
|
31010
|
+
el.stop();
|
|
31011
|
+
});
|
|
31005
31012
|
});
|
|
31006
31013
|
}
|
|
31007
31014
|
function pauseRecording() {
|
|
@@ -31359,56 +31366,6 @@ var ObjectDetection = class extends BaseDetection {
|
|
|
31359
31366
|
}
|
|
31360
31367
|
};
|
|
31361
31368
|
|
|
31362
|
-
// src/new-flow/recorders/VolumeMeter.ts
|
|
31363
|
-
var VolumeMeter = class {
|
|
31364
|
-
constructor(stream4) {
|
|
31365
|
-
this.volume = null;
|
|
31366
|
-
this.animationFrameId = null;
|
|
31367
|
-
this.stream = stream4;
|
|
31368
|
-
}
|
|
31369
|
-
async start(options = {}) {
|
|
31370
|
-
return new Promise((resolve, reject) => {
|
|
31371
|
-
try {
|
|
31372
|
-
this.audioContext = new AudioContext();
|
|
31373
|
-
this.analyser = this.audioContext.createAnalyser();
|
|
31374
|
-
this.microphone = this.audioContext.createMediaStreamSource(this.stream);
|
|
31375
|
-
this.analyser.smoothingTimeConstant = 0.8;
|
|
31376
|
-
this.analyser.fftSize = 1024;
|
|
31377
|
-
this.microphone.connect(this.analyser);
|
|
31378
|
-
const processAudio = () => {
|
|
31379
|
-
const array = new Uint8Array(this.analyser.frequencyBinCount);
|
|
31380
|
-
this.analyser.getByteFrequencyData(array);
|
|
31381
|
-
const arraySum = array.reduce((a3, value) => a3 + value, 0);
|
|
31382
|
-
const average = arraySum / array.length;
|
|
31383
|
-
this.setVolume(average);
|
|
31384
|
-
options.setVolume && options.setVolume(average);
|
|
31385
|
-
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
31386
|
-
};
|
|
31387
|
-
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
31388
|
-
resolve(true);
|
|
31389
|
-
} catch (error) {
|
|
31390
|
-
this.stop();
|
|
31391
|
-
reject(`Error: ${error}`);
|
|
31392
|
-
}
|
|
31393
|
-
});
|
|
31394
|
-
}
|
|
31395
|
-
stop() {
|
|
31396
|
-
var _a2, _b, _c2;
|
|
31397
|
-
if (this.animationFrameId !== null) {
|
|
31398
|
-
cancelAnimationFrame(this.animationFrameId);
|
|
31399
|
-
}
|
|
31400
|
-
(_a2 = this.audioContext) == null ? void 0 : _a2.close();
|
|
31401
|
-
(_b = this.microphone) == null ? void 0 : _b.disconnect();
|
|
31402
|
-
(_c2 = this.analyser) == null ? void 0 : _c2.disconnect();
|
|
31403
|
-
}
|
|
31404
|
-
getVolume() {
|
|
31405
|
-
return this.volume;
|
|
31406
|
-
}
|
|
31407
|
-
setVolume(value) {
|
|
31408
|
-
this.volume = value;
|
|
31409
|
-
}
|
|
31410
|
-
};
|
|
31411
|
-
|
|
31412
31369
|
// src/new-flow/chunk/ChunkStorageService.ts
|
|
31413
31370
|
var _ChunkStorageService = class _ChunkStorageService {
|
|
31414
31371
|
constructor() {
|
|
@@ -31425,13 +31382,7 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31425
31382
|
_ChunkStorageService.DB_VERSION
|
|
31426
31383
|
);
|
|
31427
31384
|
request.onerror = () => {
|
|
31428
|
-
|
|
31429
|
-
console.error("IndexedDB error:", request.error);
|
|
31430
|
-
reject(
|
|
31431
|
-
new Error(
|
|
31432
|
-
`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}`
|
|
31433
|
-
)
|
|
31434
|
-
);
|
|
31385
|
+
reject(new Error("N\xE3o foi poss\xEDvel conectar ao IndexedDB para chunks."));
|
|
31435
31386
|
};
|
|
31436
31387
|
request.onupgradeneeded = () => {
|
|
31437
31388
|
const db = request.result;
|
|
@@ -31654,8 +31605,8 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31654
31605
|
}
|
|
31655
31606
|
};
|
|
31656
31607
|
_ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
|
|
31657
|
-
/**
|
|
31658
|
-
_ChunkStorageService.DB_VERSION =
|
|
31608
|
+
/** v2: índices uploaded numéricos; v3: campo arrayBuffer em vez de blob */
|
|
31609
|
+
_ChunkStorageService.DB_VERSION = 3;
|
|
31659
31610
|
_ChunkStorageService.STORE_NAME = "chunks";
|
|
31660
31611
|
var ChunkStorageService = _ChunkStorageService;
|
|
31661
31612
|
|
|
@@ -31838,8 +31789,9 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31838
31789
|
let virtualStart = this.totalBytesPurged;
|
|
31839
31790
|
const chunksWithMeta = allChunks.map((c3) => {
|
|
31840
31791
|
const start = virtualStart;
|
|
31841
|
-
const
|
|
31842
|
-
|
|
31792
|
+
const byteLength = c3.arrayBuffer.byteLength;
|
|
31793
|
+
const end = start + byteLength - 1;
|
|
31794
|
+
virtualStart += byteLength;
|
|
31843
31795
|
return { chunk: c3, start, end };
|
|
31844
31796
|
});
|
|
31845
31797
|
let combinedBlobParts = [];
|
|
@@ -31849,8 +31801,8 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31849
31801
|
for (const meta of chunksWithMeta) {
|
|
31850
31802
|
if (this.currentOffset > meta.end) continue;
|
|
31851
31803
|
const sliceStart = Math.max(0, this.currentOffset - meta.start);
|
|
31852
|
-
const
|
|
31853
|
-
combinedBlobParts.push(
|
|
31804
|
+
const sliceBuf = meta.chunk.arrayBuffer.slice(sliceStart);
|
|
31805
|
+
combinedBlobParts.push(new Blob([sliceBuf]));
|
|
31854
31806
|
lastProcessedChunkId = meta.chunk.id;
|
|
31855
31807
|
finalChunkIndex = meta.chunk.chunkIndex;
|
|
31856
31808
|
}
|
|
@@ -31884,7 +31836,10 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31884
31836
|
}
|
|
31885
31837
|
if (this.config.cleanAfterUpload) {
|
|
31886
31838
|
const chunksToClear = chunksWithMeta.filter((meta) => meta.chunk.uploaded === 1 || meta.chunk.uploaded === 0 && meta.end < this.currentOffset);
|
|
31887
|
-
const sizePurged = chunksToClear.reduce(
|
|
31839
|
+
const sizePurged = chunksToClear.reduce(
|
|
31840
|
+
(acc, meta) => acc + meta.chunk.arrayBuffer.byteLength,
|
|
31841
|
+
0
|
|
31842
|
+
);
|
|
31888
31843
|
await this.chunkStorage.clearUploadedChunks(this.proctoringId);
|
|
31889
31844
|
if (sizePurged > 0) {
|
|
31890
31845
|
this.totalBytesPurged += sizePurged;
|
|
@@ -32088,7 +32043,6 @@ var _CameraRecorder = class _CameraRecorder {
|
|
|
32088
32043
|
this.currentRetries = 0;
|
|
32089
32044
|
this.packageCount = 0;
|
|
32090
32045
|
this.failedUploads = 0;
|
|
32091
|
-
this.noiseWait = 20;
|
|
32092
32046
|
this.options = options;
|
|
32093
32047
|
this.videoOptions = videoOptions;
|
|
32094
32048
|
this.backend = backend;
|
|
@@ -32510,10 +32464,11 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32510
32464
|
const savePromise = (async () => {
|
|
32511
32465
|
var _a2;
|
|
32512
32466
|
try {
|
|
32467
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
32513
32468
|
await this.chunkStorage.saveChunk({
|
|
32514
32469
|
proctoringId: this.proctoringId,
|
|
32515
32470
|
chunkIndex: this.chunkIndex,
|
|
32516
|
-
|
|
32471
|
+
arrayBuffer,
|
|
32517
32472
|
timestamp: Date.now(),
|
|
32518
32473
|
uploaded: 0,
|
|
32519
32474
|
mimeType: ((_a2 = this.recorderOptions) == null ? void 0 : _a2.mimeType) || "video/webm"
|
|
@@ -32668,35 +32623,36 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32668
32623
|
const settings = this.cameraStream.getVideoTracks()[0].getSettings();
|
|
32669
32624
|
const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
|
|
32670
32625
|
if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
|
|
32626
|
+
let isUploaded = false;
|
|
32671
32627
|
if (this.isChunkEnabled) {
|
|
32672
|
-
|
|
32673
|
-
|
|
32674
|
-
|
|
32675
|
-
|
|
32676
|
-
|
|
32677
|
-
const objectName = `${this.proctoringId}/${fileName}`;
|
|
32678
|
-
const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
|
|
32679
|
-
if (isUploaded) {
|
|
32680
|
-
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
32681
|
-
return;
|
|
32682
|
-
}
|
|
32683
|
-
}
|
|
32628
|
+
if (this.backend && this.backendToken && this.proctoringId) {
|
|
32629
|
+
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
32630
|
+
const objectName = `${this.proctoringId}/${fileName}`;
|
|
32631
|
+
isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
|
|
32632
|
+
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
32684
32633
|
}
|
|
32685
32634
|
}
|
|
32686
|
-
|
|
32687
|
-
|
|
32688
|
-
|
|
32689
|
-
|
|
32690
|
-
|
|
32691
|
-
|
|
32635
|
+
if (!isUploaded) {
|
|
32636
|
+
const rawBlob = new Blob(this.blobs, {
|
|
32637
|
+
type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
|
|
32638
|
+
});
|
|
32639
|
+
let finalBlob = rawBlob;
|
|
32640
|
+
if (typeof fixWebmDuration === "function") {
|
|
32641
|
+
finalBlob = await fixWebmDuration(rawBlob, this.duration);
|
|
32642
|
+
} else {
|
|
32643
|
+
console.warn("fixWebmDuration n\xE3o dispon\xEDvel");
|
|
32644
|
+
}
|
|
32645
|
+
session.addRecording({
|
|
32646
|
+
device: `Audio
|
|
32692
32647
|
Sample Rate: ${settingsAudio.sampleRate}
|
|
32693
32648
|
Sample Size: ${settingsAudio.sampleSize}
|
|
32694
32649
|
|
|
32695
32650
|
Video:
|
|
32696
32651
|
${JSON.stringify(this.recorderOptions)}`,
|
|
32697
|
-
|
|
32698
|
-
|
|
32699
|
-
|
|
32652
|
+
arrayBuffer: await finalBlob.arrayBuffer(),
|
|
32653
|
+
origin: "Camera" /* Camera */
|
|
32654
|
+
});
|
|
32655
|
+
}
|
|
32700
32656
|
}
|
|
32701
32657
|
}
|
|
32702
32658
|
async getFile(file, name, type) {
|
|
@@ -32709,51 +32665,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32709
32665
|
});
|
|
32710
32666
|
});
|
|
32711
32667
|
}
|
|
32712
|
-
/**
|
|
32713
|
-
* Verifica se a internet está estável para realizar o upload do vídeo na íntegra.
|
|
32714
|
-
*/
|
|
32715
|
-
async checkInternetStability() {
|
|
32716
|
-
var _a2;
|
|
32717
|
-
if (!navigator.onLine) return false;
|
|
32718
|
-
try {
|
|
32719
|
-
const controller = new AbortController();
|
|
32720
|
-
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
32721
|
-
const baseUrl = (_a2 = this.backend) == null ? void 0 : _a2.getBaseUrl();
|
|
32722
|
-
if (!baseUrl) return true;
|
|
32723
|
-
const response = await fetch(`${baseUrl}/Client/health`, {
|
|
32724
|
-
method: "GET",
|
|
32725
|
-
signal: controller.signal
|
|
32726
|
-
});
|
|
32727
|
-
clearTimeout(timeoutId);
|
|
32728
|
-
return response.status < 500;
|
|
32729
|
-
} catch (e3) {
|
|
32730
|
-
console.warn("[CameraRecorder] Internet inst\xE1vel ou lenta detectada para upload integral.");
|
|
32731
|
-
return false;
|
|
32732
|
-
}
|
|
32733
|
-
}
|
|
32734
|
-
onNoiseDetected() {
|
|
32735
|
-
var _a2, _b, _c2;
|
|
32736
|
-
if (this.options.proctoringType === "REALTIME") return;
|
|
32737
|
-
if (!this.volumeMeter && this.cameraStream) {
|
|
32738
|
-
this.volumeMeter = new VolumeMeter(this.cameraStream);
|
|
32739
|
-
this.volumeMeter.start().catch((e3) => {
|
|
32740
|
-
console.log(e3);
|
|
32741
|
-
this.volumeMeter = void 0;
|
|
32742
|
-
});
|
|
32743
|
-
}
|
|
32744
|
-
const volume = (_b = (_a2 = this.volumeMeter) == null ? void 0 : _a2.getVolume()) != null ? _b : 0;
|
|
32745
|
-
if (volume >= (((_c2 = this.paramsConfig.audioBehaviourParameters) == null ? void 0 : _c2.noiseLimit) || 40)) {
|
|
32746
|
-
if (this.noiseWait >= 20) {
|
|
32747
|
-
this.options.onRealtimeAlertsCallback({
|
|
32748
|
-
status: "ALERT",
|
|
32749
|
-
description: "Barulho detectado",
|
|
32750
|
-
type: "audio_detection_on_stream"
|
|
32751
|
-
});
|
|
32752
|
-
this.noiseWait = 0;
|
|
32753
|
-
}
|
|
32754
|
-
}
|
|
32755
|
-
this.noiseWait++;
|
|
32756
|
-
}
|
|
32757
32668
|
};
|
|
32758
32669
|
// ========================
|
|
32759
32670
|
// Chunk & Lifecycle
|
|
@@ -32764,10 +32675,62 @@ _CameraRecorder.CHUNK_TIMESLICE_MS = 6e4;
|
|
|
32764
32675
|
_CameraRecorder.LS_SESSION_KEY = "ep_proctoring_session";
|
|
32765
32676
|
var CameraRecorder = _CameraRecorder;
|
|
32766
32677
|
|
|
32678
|
+
// src/new-flow/recorders/VolumeMeter.ts
|
|
32679
|
+
var VolumeMeter = class {
|
|
32680
|
+
constructor(stream4) {
|
|
32681
|
+
this.volume = null;
|
|
32682
|
+
this.animationFrameId = null;
|
|
32683
|
+
this.stream = stream4;
|
|
32684
|
+
}
|
|
32685
|
+
async start(options = {}) {
|
|
32686
|
+
return new Promise((resolve, reject) => {
|
|
32687
|
+
try {
|
|
32688
|
+
this.audioContext = new AudioContext();
|
|
32689
|
+
this.analyser = this.audioContext.createAnalyser();
|
|
32690
|
+
this.microphone = this.audioContext.createMediaStreamSource(this.stream);
|
|
32691
|
+
this.analyser.smoothingTimeConstant = 0.8;
|
|
32692
|
+
this.analyser.fftSize = 1024;
|
|
32693
|
+
this.microphone.connect(this.analyser);
|
|
32694
|
+
const processAudio = () => {
|
|
32695
|
+
const array = new Uint8Array(this.analyser.frequencyBinCount);
|
|
32696
|
+
this.analyser.getByteFrequencyData(array);
|
|
32697
|
+
const arraySum = array.reduce((a3, value) => a3 + value, 0);
|
|
32698
|
+
const average = arraySum / array.length;
|
|
32699
|
+
this.setVolume(average);
|
|
32700
|
+
options.setVolume && options.setVolume(average);
|
|
32701
|
+
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
32702
|
+
};
|
|
32703
|
+
this.animationFrameId = requestAnimationFrame(processAudio);
|
|
32704
|
+
resolve(true);
|
|
32705
|
+
} catch (error) {
|
|
32706
|
+
this.stop();
|
|
32707
|
+
reject(`Error: ${error}`);
|
|
32708
|
+
}
|
|
32709
|
+
});
|
|
32710
|
+
}
|
|
32711
|
+
stop() {
|
|
32712
|
+
var _a2, _b, _c2;
|
|
32713
|
+
if (this.animationFrameId !== null) {
|
|
32714
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
32715
|
+
}
|
|
32716
|
+
(_a2 = this.audioContext) == null ? void 0 : _a2.close();
|
|
32717
|
+
(_b = this.microphone) == null ? void 0 : _b.disconnect();
|
|
32718
|
+
(_c2 = this.analyser) == null ? void 0 : _c2.disconnect();
|
|
32719
|
+
}
|
|
32720
|
+
getVolume() {
|
|
32721
|
+
return this.volume;
|
|
32722
|
+
}
|
|
32723
|
+
setVolume(value) {
|
|
32724
|
+
this.volume = value;
|
|
32725
|
+
}
|
|
32726
|
+
};
|
|
32727
|
+
|
|
32767
32728
|
// src/new-flow/checkers/DeviceCheckerUI.ts
|
|
32768
32729
|
var DeviceCheckerUI = class {
|
|
32769
32730
|
constructor(options = getDefaultProctoringOptions, _videoOptions) {
|
|
32770
32731
|
this.videoOptions = { width: 1080, height: 720, minWidth: 0, minHeight: 0 };
|
|
32732
|
+
this.autoConfirmTimer = null;
|
|
32733
|
+
this.autoConfirmSeconds = 5;
|
|
32771
32734
|
this.options = {
|
|
32772
32735
|
...getDefaultProctoringOptions,
|
|
32773
32736
|
...options,
|
|
@@ -33533,9 +33496,53 @@ var DeviceCheckerUI = class {
|
|
|
33533
33496
|
}));
|
|
33534
33497
|
}
|
|
33535
33498
|
closeModal() {
|
|
33499
|
+
this.stopAutoConfirm();
|
|
33536
33500
|
const checkDevices = document.querySelector("#checkDevices");
|
|
33537
33501
|
checkDevices == null ? void 0 : checkDevices.remove();
|
|
33538
33502
|
}
|
|
33503
|
+
verifyAutoConfirm(status) {
|
|
33504
|
+
var _a2;
|
|
33505
|
+
if (!((_a2 = this.options) == null ? void 0 : _a2.auto)) return;
|
|
33506
|
+
let isAllGreen = status.allowedResolution && status.allowedPositionFace && status.allowedAmbient && status.allowedMicrophone;
|
|
33507
|
+
if (this.options.useSpyScan) {
|
|
33508
|
+
isAllGreen = isAllGreen && status.allowedSpyScan === true;
|
|
33509
|
+
}
|
|
33510
|
+
if (isAllGreen) {
|
|
33511
|
+
if (!this.autoConfirmTimer) {
|
|
33512
|
+
this.startAutoConfirm();
|
|
33513
|
+
}
|
|
33514
|
+
} else {
|
|
33515
|
+
if (this.autoConfirmTimer) {
|
|
33516
|
+
this.stopAutoConfirm();
|
|
33517
|
+
}
|
|
33518
|
+
}
|
|
33519
|
+
}
|
|
33520
|
+
startAutoConfirm() {
|
|
33521
|
+
this.autoConfirmSeconds = 5;
|
|
33522
|
+
const btn = document.getElementById("confirmBtn");
|
|
33523
|
+
if (btn && !btn.disabled) {
|
|
33524
|
+
btn.innerText = `Continuando em ${this.autoConfirmSeconds}s...`;
|
|
33525
|
+
this.autoConfirmTimer = setInterval(() => {
|
|
33526
|
+
this.autoConfirmSeconds--;
|
|
33527
|
+
if (this.autoConfirmSeconds <= 0) {
|
|
33528
|
+
this.stopAutoConfirm();
|
|
33529
|
+
btn.click();
|
|
33530
|
+
} else {
|
|
33531
|
+
btn.innerText = `Continuando em ${this.autoConfirmSeconds}s...`;
|
|
33532
|
+
}
|
|
33533
|
+
}, 1e3);
|
|
33534
|
+
}
|
|
33535
|
+
}
|
|
33536
|
+
stopAutoConfirm() {
|
|
33537
|
+
if (this.autoConfirmTimer) {
|
|
33538
|
+
clearInterval(this.autoConfirmTimer);
|
|
33539
|
+
this.autoConfirmTimer = null;
|
|
33540
|
+
}
|
|
33541
|
+
const btn = document.getElementById("confirmBtn");
|
|
33542
|
+
if (btn) {
|
|
33543
|
+
btn.innerText = "Continuar";
|
|
33544
|
+
}
|
|
33545
|
+
}
|
|
33539
33546
|
modalActions(closeCheckDevices) {
|
|
33540
33547
|
const cancelBtn = document.getElementById("cancelBtn");
|
|
33541
33548
|
const confirmBtn = document.getElementById("confirmBtn");
|
|
@@ -33902,6 +33909,7 @@ var _DeviceCheckerService = class _DeviceCheckerService {
|
|
|
33902
33909
|
}
|
|
33903
33910
|
}
|
|
33904
33911
|
onUpdateCallback() {
|
|
33912
|
+
var _a2;
|
|
33905
33913
|
if (typeof this.onUpdateCb === "function") {
|
|
33906
33914
|
this.onUpdateCb({
|
|
33907
33915
|
allowedResolution: this.allowedResolution,
|
|
@@ -33912,6 +33920,15 @@ var _DeviceCheckerService = class _DeviceCheckerService {
|
|
|
33912
33920
|
faceDetectionAlerts: this.faceDetectionAlerts
|
|
33913
33921
|
});
|
|
33914
33922
|
}
|
|
33923
|
+
if (((_a2 = this.options) == null ? void 0 : _a2.auto) && this.DeviceCheckerUI) {
|
|
33924
|
+
this.DeviceCheckerUI.verifyAutoConfirm({
|
|
33925
|
+
allowedResolution: this.allowedResolution,
|
|
33926
|
+
allowedPositionFace: this.allowedPositionFace,
|
|
33927
|
+
allowedAmbient: this.allowedAmbient,
|
|
33928
|
+
allowedMicrophone: this.allowedMicrophone,
|
|
33929
|
+
allowedSpyScan: this.allowedSpyScan
|
|
33930
|
+
});
|
|
33931
|
+
}
|
|
33915
33932
|
}
|
|
33916
33933
|
async checkDevices(options = getDefaultProctoringOptions, _videoOptions = getDefaultProctoringVideoOptions) {
|
|
33917
33934
|
var _a2;
|
|
@@ -34118,16 +34135,19 @@ var _DeviceCheckerService = class _DeviceCheckerService {
|
|
|
34118
34135
|
}).finally(() => {
|
|
34119
34136
|
this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
|
|
34120
34137
|
this.DeviceCheckerUI && this.allowedSpyScan != null && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
|
|
34138
|
+
this.onUpdateCallback();
|
|
34121
34139
|
});
|
|
34122
34140
|
} else {
|
|
34123
34141
|
this.allowedSpyScan = false;
|
|
34124
34142
|
this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
|
|
34125
34143
|
this.DeviceCheckerUI && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
|
|
34144
|
+
this.onUpdateCallback();
|
|
34126
34145
|
}
|
|
34127
34146
|
} catch (error) {
|
|
34128
34147
|
this.allowedSpyScan = false;
|
|
34129
34148
|
this.DeviceCheckerUI && this.DeviceCheckerUI.waitingSpyDevices(false);
|
|
34130
34149
|
this.DeviceCheckerUI && this.DeviceCheckerUI.isSpyDevicesUI(this.allowedSpyScan);
|
|
34150
|
+
this.onUpdateCallback();
|
|
34131
34151
|
console.log(error);
|
|
34132
34152
|
}
|
|
34133
34153
|
}
|
|
@@ -34447,8 +34467,8 @@ var CapturePhoto = class {
|
|
|
34447
34467
|
}
|
|
34448
34468
|
};
|
|
34449
34469
|
|
|
34450
|
-
// src/extension/
|
|
34451
|
-
var
|
|
34470
|
+
// src/extension/extensionEasyProctor.ts
|
|
34471
|
+
var ExtensionEasyProctor = class {
|
|
34452
34472
|
constructor() {
|
|
34453
34473
|
this.hasExtension = false;
|
|
34454
34474
|
this.tryes = 0;
|
|
@@ -34493,6 +34513,89 @@ var Extension = class {
|
|
|
34493
34513
|
}
|
|
34494
34514
|
};
|
|
34495
34515
|
|
|
34516
|
+
// src/extension/extensionEasyCatcher.ts
|
|
34517
|
+
var ExtensionEasyCatcher = class {
|
|
34518
|
+
constructor(options) {
|
|
34519
|
+
this.hasExtension = false;
|
|
34520
|
+
this.tryes = 0;
|
|
34521
|
+
this.responseStart = false;
|
|
34522
|
+
this.options = options || {};
|
|
34523
|
+
}
|
|
34524
|
+
/**
|
|
34525
|
+
* Verifica se a extensão está instalada e ativa.
|
|
34526
|
+
* Retorna o número da versão se encontrada, ou lança erro após timeout.
|
|
34527
|
+
*/
|
|
34528
|
+
checkExtensionInstalled(timeoutMs = 2e3) {
|
|
34529
|
+
return new Promise((resolve, reject) => {
|
|
34530
|
+
let handled = false;
|
|
34531
|
+
const handler = (event) => {
|
|
34532
|
+
if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "version") {
|
|
34533
|
+
handled = true;
|
|
34534
|
+
window.removeEventListener("message", handler);
|
|
34535
|
+
resolve(event.data.message);
|
|
34536
|
+
}
|
|
34537
|
+
};
|
|
34538
|
+
window.addEventListener("message", handler);
|
|
34539
|
+
window.postMessage({
|
|
34540
|
+
type: "easycatcher",
|
|
34541
|
+
func: "verifyExtensionEasycatcher"
|
|
34542
|
+
}, "*");
|
|
34543
|
+
setTimeout(() => {
|
|
34544
|
+
if (!handled) {
|
|
34545
|
+
window.removeEventListener("message", handler);
|
|
34546
|
+
reject(new Error("Extens\xE3o n\xE3o detectada ou n\xE3o respondeu."));
|
|
34547
|
+
}
|
|
34548
|
+
}, timeoutMs);
|
|
34549
|
+
});
|
|
34550
|
+
}
|
|
34551
|
+
/**
|
|
34552
|
+
* Solicita o JSON da sessão atual capturado pela extensão.
|
|
34553
|
+
*/
|
|
34554
|
+
getSessionData(timeoutMs = 5e3) {
|
|
34555
|
+
return new Promise((resolve, reject) => {
|
|
34556
|
+
let handled = false;
|
|
34557
|
+
const handler = (event) => {
|
|
34558
|
+
if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "data_response") {
|
|
34559
|
+
handled = true;
|
|
34560
|
+
window.removeEventListener("message", handler);
|
|
34561
|
+
resolve(event.data.payload);
|
|
34562
|
+
}
|
|
34563
|
+
};
|
|
34564
|
+
window.addEventListener("message", handler);
|
|
34565
|
+
window.postMessage({
|
|
34566
|
+
type: "easycatcher",
|
|
34567
|
+
func: "getDataExtensionEasycatcher"
|
|
34568
|
+
}, "*");
|
|
34569
|
+
setTimeout(() => {
|
|
34570
|
+
if (!handled) {
|
|
34571
|
+
window.removeEventListener("message", handler);
|
|
34572
|
+
reject(new Error("Timeout ao aguardar dados da extens\xE3o."));
|
|
34573
|
+
}
|
|
34574
|
+
}, timeoutMs);
|
|
34575
|
+
});
|
|
34576
|
+
}
|
|
34577
|
+
start() {
|
|
34578
|
+
return new Promise((resolve, reject) => {
|
|
34579
|
+
let handled = false;
|
|
34580
|
+
const handler = (event) => {
|
|
34581
|
+
if (event.source === window && event.data.sender === "easyproctor-extension" && event.data.message_name === "started_confirmed") {
|
|
34582
|
+
handled = true;
|
|
34583
|
+
window.removeEventListener("message", handler);
|
|
34584
|
+
resolve(true);
|
|
34585
|
+
}
|
|
34586
|
+
};
|
|
34587
|
+
window.addEventListener("message", handler);
|
|
34588
|
+
window.postMessage({ type: "easycatcher", func: "startExtensionEasycatcher" }, "*");
|
|
34589
|
+
setTimeout(() => {
|
|
34590
|
+
if (!handled) {
|
|
34591
|
+
window.removeEventListener("message", handler);
|
|
34592
|
+
reject(new Error("Timeout: Extens\xE3o n\xE3o confirmou o in\xEDcio."));
|
|
34593
|
+
}
|
|
34594
|
+
}, 3e3);
|
|
34595
|
+
});
|
|
34596
|
+
}
|
|
34597
|
+
};
|
|
34598
|
+
|
|
34496
34599
|
// src/modules/onChangeDevices.ts
|
|
34497
34600
|
var onChangeDevices = class {
|
|
34498
34601
|
constructor(repositoryDevices, proctoringId2, sessionOptions, allRecorders) {
|
|
@@ -38820,7 +38923,10 @@ var Proctoring = class {
|
|
|
38820
38923
|
if (this.context.token === void 0) {
|
|
38821
38924
|
throw TOKEN_MISSING;
|
|
38822
38925
|
}
|
|
38823
|
-
|
|
38926
|
+
if (options.useChallenge) {
|
|
38927
|
+
this.extensionEasycatcher = new ExtensionEasyCatcher();
|
|
38928
|
+
}
|
|
38929
|
+
this.extension = new ExtensionEasyProctor();
|
|
38824
38930
|
this.extension.addEventListener();
|
|
38825
38931
|
const baseURL = this.backend.selectBaseUrl(this.context.type);
|
|
38826
38932
|
const devices = await enumarateDevices();
|
|
@@ -38888,20 +38994,6 @@ var Proctoring = class {
|
|
|
38888
38994
|
} catch (error) {
|
|
38889
38995
|
throw SAFE_BROWSER_API_NOT_FOUND;
|
|
38890
38996
|
}
|
|
38891
|
-
this.allRecorders.cameraRecorder.onVisibilityRestored = () => {
|
|
38892
|
-
console.log("[Proctoring] Usu\xE1rio retornou ao browser.");
|
|
38893
|
-
this.onVisibilityRestoredCallback();
|
|
38894
|
-
};
|
|
38895
|
-
if (this.sessionOptions.proctoringType === "REALTIME" && !isSafeBrowser()) {
|
|
38896
|
-
try {
|
|
38897
|
-
await BackgroundUploadService.recoverPendingUploads(
|
|
38898
|
-
this.backend,
|
|
38899
|
-
this.context.token
|
|
38900
|
-
);
|
|
38901
|
-
} catch (e3) {
|
|
38902
|
-
console.warn("[Proctoring] Erro ao recuperar chunks de sess\xE3o anterior:", e3);
|
|
38903
|
-
}
|
|
38904
|
-
}
|
|
38905
38997
|
try {
|
|
38906
38998
|
console.log("Starting recorders");
|
|
38907
38999
|
await this.recorder.startAll();
|
|
@@ -38982,7 +39074,9 @@ Error: ${error}`
|
|
|
38982
39074
|
this.appChecker && await this.appChecker.disconnectWebSocket();
|
|
38983
39075
|
await this.recorder.saveAllOnSession();
|
|
38984
39076
|
await this.sendPendingRealtimeAlerts();
|
|
39077
|
+
trackers.registerError(this.proctoringId, `finish this.repository.save starting`);
|
|
38985
39078
|
await this.repository.save(this.proctoringSession);
|
|
39079
|
+
trackers.registerError(this.proctoringId, `finish this.repository.save finished`);
|
|
38986
39080
|
let uploader;
|
|
38987
39081
|
let uploaderServices;
|
|
38988
39082
|
if (versionVerify() !== "1.0.0.0") {
|
|
@@ -39204,6 +39298,61 @@ Error: ` + error
|
|
|
39204
39298
|
_screenStream: (_a2 = this.allRecorders.screenRecorder) == null ? void 0 : _a2.screenStream
|
|
39205
39299
|
};
|
|
39206
39300
|
}
|
|
39301
|
+
async startChallenge(templateId) {
|
|
39302
|
+
var _a2;
|
|
39303
|
+
if (!this.sessionOptions.useChallenge) {
|
|
39304
|
+
throw new Error("useChallenge is set as false on start method");
|
|
39305
|
+
}
|
|
39306
|
+
await this.extensionEasycatcher.checkExtensionInstalled().catch((err) => {
|
|
39307
|
+
throw new Error("EasyCatcher Extension is not installed");
|
|
39308
|
+
});
|
|
39309
|
+
this.extensionEasycatcher.start();
|
|
39310
|
+
const start = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
|
|
39311
|
+
await this.backend.startChallenge({
|
|
39312
|
+
proctoringId: this.proctoringId,
|
|
39313
|
+
templateId,
|
|
39314
|
+
start
|
|
39315
|
+
}).then((resp) => {
|
|
39316
|
+
console.log(resp);
|
|
39317
|
+
this.challengeId = resp.id;
|
|
39318
|
+
}).catch((reason) => {
|
|
39319
|
+
trackers.registerError(
|
|
39320
|
+
this.proctoringId,
|
|
39321
|
+
"N\xE3o foi poss\xEDvel iniciar desafio!"
|
|
39322
|
+
);
|
|
39323
|
+
throw reason;
|
|
39324
|
+
});
|
|
39325
|
+
this.isChallengeRunning = true;
|
|
39326
|
+
}
|
|
39327
|
+
async stopChallenge() {
|
|
39328
|
+
var _a2;
|
|
39329
|
+
if (!this.isChallengeRunning) {
|
|
39330
|
+
throw new Error("Challenge not started");
|
|
39331
|
+
}
|
|
39332
|
+
try {
|
|
39333
|
+
const sessionData = await this.extensionEasycatcher.getSessionData();
|
|
39334
|
+
const end = Date.now() - ((_a2 = this.allRecorders.cameraRecorder.getStartTime()) == null ? void 0 : _a2.getTime()) || 0;
|
|
39335
|
+
await this.backend.stopChallenge(
|
|
39336
|
+
this.challengeId,
|
|
39337
|
+
{
|
|
39338
|
+
end,
|
|
39339
|
+
data: sessionData
|
|
39340
|
+
}
|
|
39341
|
+
).catch((reason) => {
|
|
39342
|
+
trackers.registerError(
|
|
39343
|
+
this.proctoringId,
|
|
39344
|
+
"N\xE3o foi poss\xEDvel finalizar o desafio no backend!"
|
|
39345
|
+
);
|
|
39346
|
+
return void 0;
|
|
39347
|
+
});
|
|
39348
|
+
this.isChallengeRunning = false;
|
|
39349
|
+
} catch (error) {
|
|
39350
|
+
trackers.registerError(
|
|
39351
|
+
this.proctoringId,
|
|
39352
|
+
"Erro ao recuperar dados da extens\xE3o: " + error.message
|
|
39353
|
+
);
|
|
39354
|
+
}
|
|
39355
|
+
}
|
|
39207
39356
|
};
|
|
39208
39357
|
|
|
39209
39358
|
// src/proctoring/SignTerm.ts
|
|
@@ -39432,6 +39581,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
|
|
|
39432
39581
|
return originalStart(parameters2, videoOptions);
|
|
39433
39582
|
};
|
|
39434
39583
|
const finish = proctoring.finish.bind(proctoring);
|
|
39584
|
+
const startChallenge = proctoring.startChallenge.bind(proctoring);
|
|
39585
|
+
const stopChallenge = proctoring.stopChallenge.bind(proctoring);
|
|
39435
39586
|
const pause = proctoring.pause.bind(proctoring);
|
|
39436
39587
|
const resume = proctoring.resume.bind(proctoring);
|
|
39437
39588
|
const onFocus = proctoring.setOnFocusCallback.bind(proctoring);
|
|
@@ -39456,6 +39607,8 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
|
|
|
39456
39607
|
login,
|
|
39457
39608
|
start,
|
|
39458
39609
|
finish,
|
|
39610
|
+
startChallenge,
|
|
39611
|
+
stopChallenge,
|
|
39459
39612
|
onFocus,
|
|
39460
39613
|
onLostFocus,
|
|
39461
39614
|
onChangeDevices: onChangeDevices2,
|
|
@@ -12,6 +12,8 @@ export declare class DeviceCheckerUI {
|
|
|
12
12
|
videoOptions: ProctoringVideoOptions;
|
|
13
13
|
cameraRecorder: CameraRecorder;
|
|
14
14
|
volumeMeter: VolumeMeter | undefined;
|
|
15
|
+
private autoConfirmTimer;
|
|
16
|
+
private autoConfirmSeconds;
|
|
15
17
|
constructor(options: ProctoringSessionOptions | undefined, _videoOptions: ProctoringVideoOptions);
|
|
16
18
|
checkDevicesInterface(): void;
|
|
17
19
|
setSelectOption(options: ProctoringSessionOptions, changeSelectedDevice: (arg0: {
|
|
@@ -29,6 +31,15 @@ export declare class DeviceCheckerUI {
|
|
|
29
31
|
}): any;
|
|
30
32
|
}): Promise<void>;
|
|
31
33
|
closeModal(): void;
|
|
34
|
+
verifyAutoConfirm(status: {
|
|
35
|
+
allowedResolution: boolean;
|
|
36
|
+
allowedPositionFace: boolean;
|
|
37
|
+
allowedAmbient: boolean;
|
|
38
|
+
allowedMicrophone: boolean;
|
|
39
|
+
allowedSpyScan: boolean | null;
|
|
40
|
+
}): void;
|
|
41
|
+
private startAutoConfirm;
|
|
42
|
+
private stopAutoConfirm;
|
|
32
43
|
modalActions(closeCheckDevices: {
|
|
33
44
|
(): Promise<void>;
|
|
34
45
|
(): void;
|