easyproctor 2.5.2 → 2.5.3
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 +3 -0
- package/esm/index.js +270 -70
- package/index.js +270 -70
- package/interfaces/ParamsConfig.d.ts +0 -1
- package/new-flow/backend/BackendService.d.ts +1 -1
- package/new-flow/proctoring/ProctoringSession.d.ts +5 -2
- package/new-flow/recorders/AlertRecorder.d.ts +18 -2
- package/package.json +1 -1
- package/proctoring/proctoring.d.ts +1 -0
- package/proctoring/useProctoring.d.ts +1 -1
- package/unpkg/easyproctor.min.js +39 -39
package/index.js
CHANGED
|
@@ -26076,6 +26076,14 @@ var BaseDetection = class {
|
|
|
26076
26076
|
return "Face n\xE3o centralizada, mova-se para cima";
|
|
26077
26077
|
case "wrong_face_position_move_bottom_detected":
|
|
26078
26078
|
return "Face n\xE3o centralizada, mova-se para baixo";
|
|
26079
|
+
case "face_turned_left_detected":
|
|
26080
|
+
return "Face virada para a esquerda, centralize-a";
|
|
26081
|
+
case "face_turned_right_detected":
|
|
26082
|
+
return "Face virada para a direita, centralize-a";
|
|
26083
|
+
case "face_turned_up_detected":
|
|
26084
|
+
return "Face virada para cima, centralize-a";
|
|
26085
|
+
case "face_turned_down_detected":
|
|
26086
|
+
return "Face virada para baixo, centralize-a";
|
|
26079
26087
|
default:
|
|
26080
26088
|
return description;
|
|
26081
26089
|
}
|
|
@@ -26106,7 +26114,14 @@ function buildVideoPreview() {
|
|
|
26106
26114
|
// src/modules/faceDetection.ts
|
|
26107
26115
|
var FaceDetection = class extends BaseDetection {
|
|
26108
26116
|
constructor(options, paramsConfig, classVideo = "videoPreviewFrameDetection", classDiv = "liveViewFrameDetection") {
|
|
26109
|
-
super(
|
|
26117
|
+
super(
|
|
26118
|
+
"FaceDetector",
|
|
26119
|
+
`https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite`,
|
|
26120
|
+
options,
|
|
26121
|
+
paramsConfig,
|
|
26122
|
+
classVideo,
|
|
26123
|
+
classDiv
|
|
26124
|
+
);
|
|
26110
26125
|
this.emmitedPositionAlert = false;
|
|
26111
26126
|
this.emmitedFaceAlert = false;
|
|
26112
26127
|
}
|
|
@@ -26252,8 +26267,8 @@ var FaceDetection = class extends BaseDetection {
|
|
|
26252
26267
|
for (const keypoint of detection.keypoints) {
|
|
26253
26268
|
const keypointEl = document.createElement("span");
|
|
26254
26269
|
keypointEl.className = "key-point";
|
|
26255
|
-
|
|
26256
|
-
|
|
26270
|
+
const kpX = keypoint.x < 2 ? keypoint.x * videoElement.videoWidth : keypoint.x;
|
|
26271
|
+
const kpY = keypoint.y < 2 ? keypoint.y * videoElement.videoHeight : keypoint.y;
|
|
26257
26272
|
const mirroredKpX = videoElement.videoWidth - kpX;
|
|
26258
26273
|
const screenX = mirroredKpX * scaleX;
|
|
26259
26274
|
const screenY = kpY * scaleY;
|
|
@@ -26292,55 +26307,87 @@ var FaceDetection = class extends BaseDetection {
|
|
|
26292
26307
|
}
|
|
26293
26308
|
}
|
|
26294
26309
|
if (result.detections.length === 0) return;
|
|
26295
|
-
let
|
|
26296
|
-
|
|
26310
|
+
let failedFacePosition = false;
|
|
26311
|
+
const video = document.getElementById(this.classVideo);
|
|
26297
26312
|
const imageWidth = video.videoWidth;
|
|
26298
26313
|
const imageHeight = video.videoHeight;
|
|
26299
|
-
|
|
26314
|
+
const detection = result.detections[0];
|
|
26315
|
+
const face = detection.boundingBox;
|
|
26316
|
+
const keypoints = detection.keypoints;
|
|
26317
|
+
const rightEye = keypoints[0];
|
|
26318
|
+
const leftEye = keypoints[1];
|
|
26319
|
+
const mouth = keypoints[3];
|
|
26320
|
+
const rightEar = keypoints[4];
|
|
26321
|
+
const leftEar = keypoints[5];
|
|
26322
|
+
const nose = keypoints[2];
|
|
26300
26323
|
if (imageWidth > imageHeight) {
|
|
26301
26324
|
if (face.height / imageHeight > 0.7) {
|
|
26302
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26325
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26326
|
+
"wrong_face_size_detected",
|
|
26327
|
+
"position_detection_on_stream"
|
|
26328
|
+
);
|
|
26303
26329
|
failedFacePosition = true;
|
|
26304
26330
|
this.emmitedPositionAlert = true;
|
|
26305
26331
|
} else if (face.width / imageWidth > 0.7) {
|
|
26306
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26332
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26333
|
+
"wrong_face_size_detected",
|
|
26334
|
+
"position_detection_on_stream"
|
|
26335
|
+
);
|
|
26307
26336
|
this.emmitedPositionAlert = true;
|
|
26308
26337
|
failedFacePosition = true;
|
|
26309
26338
|
}
|
|
26310
26339
|
}
|
|
26311
|
-
|
|
26312
|
-
|
|
26340
|
+
const start = [face.originX, face.originY];
|
|
26341
|
+
const end = [face.originX + face.width, face.originY + face.height];
|
|
26313
26342
|
if (start[0] < 0.1 * face.width || start[1] < 0.2 * face.height || end[0] > imageWidth - 0.1 * face.width || end[1] > imageHeight - 5) {
|
|
26314
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26343
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26344
|
+
"wrong_face_position_edge_detected",
|
|
26345
|
+
"position_detection_on_stream"
|
|
26346
|
+
);
|
|
26315
26347
|
this.emmitedPositionAlert = true;
|
|
26316
26348
|
failedFacePosition = true;
|
|
26317
26349
|
}
|
|
26318
|
-
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26350
|
+
const leftGap = start[0];
|
|
26351
|
+
const rightGap = imageWidth - end[0];
|
|
26352
|
+
const topGap = start[1];
|
|
26353
|
+
const bottomGap = imageHeight - end[1];
|
|
26322
26354
|
if (leftGap > 2 * rightGap) {
|
|
26323
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26355
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26356
|
+
"wrong_face_position_move_right_detected",
|
|
26357
|
+
"position_detection_on_stream"
|
|
26358
|
+
);
|
|
26324
26359
|
this.emmitedPositionAlert = true;
|
|
26325
26360
|
failedFacePosition = true;
|
|
26326
26361
|
}
|
|
26327
26362
|
if (topGap > 4 * bottomGap) {
|
|
26328
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26363
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26364
|
+
"wrong_face_position_move_top_detected",
|
|
26365
|
+
"position_detection_on_stream"
|
|
26366
|
+
);
|
|
26329
26367
|
this.emmitedPositionAlert = true;
|
|
26330
26368
|
failedFacePosition = true;
|
|
26331
26369
|
}
|
|
26332
26370
|
if (rightGap > 2 * leftGap) {
|
|
26333
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26371
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26372
|
+
"wrong_face_position_move_left_detected",
|
|
26373
|
+
"position_detection_on_stream"
|
|
26374
|
+
);
|
|
26334
26375
|
this.emmitedPositionAlert = true;
|
|
26335
26376
|
failedFacePosition = true;
|
|
26336
26377
|
}
|
|
26337
26378
|
if (bottomGap > 3 * topGap) {
|
|
26338
|
-
!this.emmitedPositionAlert && this.handleAlert(
|
|
26379
|
+
!this.emmitedPositionAlert && this.handleAlert(
|
|
26380
|
+
"wrong_face_position_move_bottom_detected",
|
|
26381
|
+
"position_detection_on_stream"
|
|
26382
|
+
);
|
|
26339
26383
|
this.emmitedPositionAlert = true;
|
|
26340
26384
|
failedFacePosition = true;
|
|
26341
26385
|
}
|
|
26342
26386
|
if (failedFacePosition == false) {
|
|
26343
|
-
this.emmitedPositionAlert && this.handleOk(
|
|
26387
|
+
this.emmitedPositionAlert && this.handleOk(
|
|
26388
|
+
"ok_position_face_detected",
|
|
26389
|
+
"position_detection_on_stream"
|
|
26390
|
+
);
|
|
26344
26391
|
this.emmitedPositionAlert = false;
|
|
26345
26392
|
}
|
|
26346
26393
|
}
|
|
@@ -29869,12 +29916,12 @@ var BackendService = class {
|
|
|
29869
29916
|
});
|
|
29870
29917
|
return result.data;
|
|
29871
29918
|
}
|
|
29872
|
-
async verifyFace(proctoringId2, faceImage) {
|
|
29919
|
+
async verifyFace(proctoringId2, faceImage, retry) {
|
|
29873
29920
|
const result = await this.makeRequestAxios({
|
|
29874
29921
|
path: `/Realtime/verify-face`,
|
|
29875
29922
|
method: "POST",
|
|
29876
29923
|
jwt: this.token,
|
|
29877
|
-
body: { "proctoringId": proctoringId2, "base64": faceImage }
|
|
29924
|
+
body: { "proctoringId": proctoringId2, "base64": faceImage, "retry": retry }
|
|
29878
29925
|
});
|
|
29879
29926
|
return result.data;
|
|
29880
29927
|
}
|
|
@@ -30750,7 +30797,6 @@ var CameraRecorder = class {
|
|
|
30750
30797
|
noiseLimit: 40
|
|
30751
30798
|
},
|
|
30752
30799
|
imageBehaviourParameters: {
|
|
30753
|
-
frames: 40,
|
|
30754
30800
|
useUploadImage: true,
|
|
30755
30801
|
uploadInterval: 20,
|
|
30756
30802
|
saveVideo: true
|
|
@@ -30762,7 +30808,6 @@ var CameraRecorder = class {
|
|
|
30762
30808
|
}
|
|
30763
30809
|
};
|
|
30764
30810
|
// private imageParams: ImageParameters = {
|
|
30765
|
-
// frames: 40,
|
|
30766
30811
|
// useUploadImage: true,
|
|
30767
30812
|
// uploadInterval: 20,
|
|
30768
30813
|
// saveVideo: true
|
|
@@ -31671,8 +31716,20 @@ var DeviceCheckerUI = class {
|
|
|
31671
31716
|
);
|
|
31672
31717
|
checkmark_FacePosition.appendChild(checkmark_stem_FacePosition);
|
|
31673
31718
|
checkmark_FacePosition.appendChild(checkmark_kick_FacePosition);
|
|
31719
|
+
const info_FacePosition = document.createElement("span");
|
|
31720
|
+
const info_stem_FacePosition = document.createElement("div");
|
|
31721
|
+
const info_kick_FacePosition = document.createElement("div");
|
|
31722
|
+
info_FacePosition.style.marginLeft = "10px";
|
|
31723
|
+
info_FacePosition.setAttribute("class", "info");
|
|
31724
|
+
info_FacePosition.setAttribute("id", "info_FacePosition");
|
|
31725
|
+
info_FacePosition.style.display = "none";
|
|
31726
|
+
info_stem_FacePosition.setAttribute("class", "info_stem");
|
|
31727
|
+
info_kick_FacePosition.setAttribute("class", "info_kick");
|
|
31728
|
+
info_FacePosition.appendChild(info_stem_FacePosition);
|
|
31729
|
+
info_FacePosition.appendChild(info_kick_FacePosition);
|
|
31674
31730
|
alertDivFacePosition.appendChild(checkmark_FacePosition);
|
|
31675
31731
|
alertDivFacePosition.appendChild(facePositionAlert);
|
|
31732
|
+
alertDivFacePosition.appendChild(info_FacePosition);
|
|
31676
31733
|
const alertDivAmbientVerify = document.createElement("div");
|
|
31677
31734
|
alertDivAmbientVerify.setAttribute("class", "alert-div");
|
|
31678
31735
|
alertDivAmbientVerify.setAttribute("id", "alertDivAmbientVerify");
|
|
@@ -32003,6 +32060,8 @@ var DeviceCheckerUI = class {
|
|
|
32003
32060
|
realtimeAlertsUI(response) {
|
|
32004
32061
|
const facePositionAlert = document.getElementById("facePositionAlert");
|
|
32005
32062
|
const ambientVerifyAlert = document.getElementById("ambientVerifyAlert");
|
|
32063
|
+
const alertDivFacePosition = document.getElementById("alertDivFacePosition");
|
|
32064
|
+
const info_FacePosition = document.getElementById("info_FacePosition");
|
|
32006
32065
|
const checkmark_FacePosition = document.getElementById("checkmark_FacePosition");
|
|
32007
32066
|
const checkmark_stem_FacePosition = document.getElementById("checkmark_stem_FacePosition");
|
|
32008
32067
|
const checkmark_kick_FacePosition = document.getElementById("checkmark_kick_FacePosition");
|
|
@@ -32013,6 +32072,8 @@ var DeviceCheckerUI = class {
|
|
|
32013
32072
|
if (response.status === "OK") {
|
|
32014
32073
|
facePositionAlert && (facePositionAlert.style.color = "#16A34A");
|
|
32015
32074
|
ambientVerifyAlert && (ambientVerifyAlert.style.color = "#16A34A");
|
|
32075
|
+
alertDivFacePosition && alertDivFacePosition.setAttribute("title", ``);
|
|
32076
|
+
info_FacePosition && (info_FacePosition.style.display = "none");
|
|
32016
32077
|
alertDivAmbientVerify && alertDivAmbientVerify.setAttribute("title", ``);
|
|
32017
32078
|
if (checkmark_FacePosition) {
|
|
32018
32079
|
checkmark_FacePosition.setAttribute("class", "checkmark");
|
|
@@ -32027,6 +32088,8 @@ var DeviceCheckerUI = class {
|
|
|
32027
32088
|
} else {
|
|
32028
32089
|
if (checkmark_FacePosition && (response.type === "position_detection_on_stream" || response.type === "face_detection_on_stream")) {
|
|
32029
32090
|
facePositionAlert && (facePositionAlert.style.color = "#FF0000");
|
|
32091
|
+
info_FacePosition && (info_FacePosition.style.display = "block");
|
|
32092
|
+
alertDivFacePosition && alertDivFacePosition.setAttribute("title", response.description);
|
|
32030
32093
|
checkmark_FacePosition.setAttribute("class", "checkmark_error");
|
|
32031
32094
|
checkmark_stem_FacePosition.setAttribute("class", "checkmark_stem_error");
|
|
32032
32095
|
checkmark_kick_FacePosition.setAttribute("class", "checkmark_kick_error");
|
|
@@ -33137,64 +33200,186 @@ var ProctoringUploader = class {
|
|
|
33137
33200
|
var AlertRecorder = class {
|
|
33138
33201
|
constructor(options, optionsProctoring) {
|
|
33139
33202
|
this.alerts = [];
|
|
33203
|
+
// Variáveis para controle de inatividade
|
|
33204
|
+
this.lastActivityTime = Date.now();
|
|
33205
|
+
this.IDLE_THRESHOLD_MS = 3e4;
|
|
33206
|
+
// ==========================================
|
|
33207
|
+
// HANDLERS (Funções Arrow para preservar o 'this')
|
|
33208
|
+
// ==========================================
|
|
33209
|
+
// 1. LOST / RETURN FOCUS
|
|
33210
|
+
this.handleLostFocus = () => {
|
|
33211
|
+
if (this.getRelativeTime() > 1e4) {
|
|
33212
|
+
const alertPayload = {
|
|
33213
|
+
begin: this.getRelativeTime(),
|
|
33214
|
+
end: 0,
|
|
33215
|
+
alert: 25 /* FocusOff */,
|
|
33216
|
+
type: 3 /* Screen */
|
|
33217
|
+
};
|
|
33218
|
+
this.onLostFocusCallback(alertPayload);
|
|
33219
|
+
this.alerts.push(alertPayload);
|
|
33220
|
+
}
|
|
33221
|
+
};
|
|
33222
|
+
this.handleReturnFocus = () => {
|
|
33223
|
+
const lastAlert = this.alerts[this.alerts.length - 1];
|
|
33224
|
+
if (lastAlert) {
|
|
33225
|
+
this.onFocusCallback({
|
|
33226
|
+
begin: lastAlert.begin,
|
|
33227
|
+
end: this.getRelativeTime(),
|
|
33228
|
+
alert: 25 /* FocusOff */,
|
|
33229
|
+
type: 3 /* Screen */
|
|
33230
|
+
});
|
|
33231
|
+
lastAlert.end = this.getRelativeTime();
|
|
33232
|
+
}
|
|
33233
|
+
};
|
|
33234
|
+
// 2. SPLIT SCREEN DETECTION
|
|
33235
|
+
this.handleResize = () => {
|
|
33236
|
+
clearTimeout(this.resizeTimeout);
|
|
33237
|
+
this.resizeTimeout = setTimeout(() => {
|
|
33238
|
+
const screenWidth = window.screen.availWidth;
|
|
33239
|
+
const windowWidth = window.outerWidth;
|
|
33240
|
+
if (windowWidth < screenWidth * 0.85) {
|
|
33241
|
+
const msg = `Split Screen Detectado: Janela ocupa ${(windowWidth / screenWidth * 100).toFixed(0)}% da tela`;
|
|
33242
|
+
this.createAlert(200 /* System */, 3 /* Screen */, msg);
|
|
33243
|
+
this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
|
|
33244
|
+
status: "ALERT",
|
|
33245
|
+
description: msg,
|
|
33246
|
+
type: "split_screen"
|
|
33247
|
+
});
|
|
33248
|
+
}
|
|
33249
|
+
}, 1e3);
|
|
33250
|
+
};
|
|
33251
|
+
// 3. DETECÇÃO DE INATIVIDADE (NO INPUT)
|
|
33252
|
+
this.handleUserActivity = (e3) => {
|
|
33253
|
+
this.lastActivityTime = Date.now();
|
|
33254
|
+
console.log("\u{1F449} handleUserActivity", e3);
|
|
33255
|
+
};
|
|
33256
|
+
// 5. CLIPBOARD HANDLERS
|
|
33257
|
+
this.handleCopy = (e3) => {
|
|
33258
|
+
e3.preventDefault();
|
|
33259
|
+
const msg = "Tentativa de Copiar (Clipboard)";
|
|
33260
|
+
this.createAlert(100 /* ForbiddenAction */, 6 /* System */, msg);
|
|
33261
|
+
this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
|
|
33262
|
+
status: "ALERT",
|
|
33263
|
+
description: msg,
|
|
33264
|
+
type: "clipboard_copy"
|
|
33265
|
+
});
|
|
33266
|
+
};
|
|
33267
|
+
this.handleCut = (e3) => {
|
|
33268
|
+
e3.preventDefault();
|
|
33269
|
+
const msg = "Tentativa de Recortar (Clipboard)";
|
|
33270
|
+
this.createAlert(100 /* ForbiddenAction */, 6 /* System */, msg);
|
|
33271
|
+
this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
|
|
33272
|
+
status: "ALERT",
|
|
33273
|
+
description: msg,
|
|
33274
|
+
type: "clipboard_cut"
|
|
33275
|
+
});
|
|
33276
|
+
};
|
|
33277
|
+
this.handlePaste = (e3) => {
|
|
33278
|
+
e3.preventDefault();
|
|
33279
|
+
const msg = "Tentativa de Colar (Clipboard)";
|
|
33280
|
+
this.createAlert(100 /* ForbiddenAction */, 6 /* System */, msg);
|
|
33281
|
+
this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
|
|
33282
|
+
status: "ALERT",
|
|
33283
|
+
description: msg,
|
|
33284
|
+
type: "clipboard_paste"
|
|
33285
|
+
});
|
|
33286
|
+
};
|
|
33140
33287
|
this.onLostFocusCallback = options.onLostFocusCallback;
|
|
33141
33288
|
this.onFocusCallback = options.onFocusCallback;
|
|
33289
|
+
this.onRealtimeAlertCallback = options.onRealtimeAlertCallback;
|
|
33142
33290
|
this.optionsProctoring = optionsProctoring;
|
|
33143
33291
|
}
|
|
33144
33292
|
async startRecording() {
|
|
33145
33293
|
this.startTime = new Date(Date.now());
|
|
33146
|
-
|
|
33147
|
-
|
|
33148
|
-
window.addEventListener("focus", () => this.onReturnFocus());
|
|
33149
|
-
}
|
|
33294
|
+
this.alerts = [];
|
|
33295
|
+
this.attachListeners();
|
|
33150
33296
|
}
|
|
33151
33297
|
async pauseRecording() {
|
|
33152
|
-
|
|
33153
|
-
window.removeEventListener("focus", () => this.onReturnFocus());
|
|
33298
|
+
this.detachListeners();
|
|
33154
33299
|
}
|
|
33155
33300
|
async resumeRecording() {
|
|
33156
|
-
|
|
33157
|
-
window.addEventListener("blur", () => this.onLostFocus());
|
|
33158
|
-
window.addEventListener("focus", () => this.onReturnFocus());
|
|
33159
|
-
}
|
|
33301
|
+
this.attachListeners();
|
|
33160
33302
|
}
|
|
33161
33303
|
async stopRecording() {
|
|
33162
|
-
|
|
33163
|
-
window.removeEventListener("focus", () => this.onReturnFocus());
|
|
33304
|
+
this.detachListeners();
|
|
33164
33305
|
}
|
|
33165
33306
|
async saveOnSession(session) {
|
|
33166
33307
|
this.alerts.forEach((alert) => {
|
|
33167
33308
|
session.addAlert(alert);
|
|
33168
33309
|
});
|
|
33169
33310
|
}
|
|
33170
|
-
|
|
33171
|
-
|
|
33172
|
-
|
|
33173
|
-
|
|
33174
|
-
|
|
33175
|
-
|
|
33176
|
-
|
|
33177
|
-
|
|
33178
|
-
|
|
33179
|
-
|
|
33180
|
-
|
|
33181
|
-
|
|
33182
|
-
|
|
33183
|
-
|
|
33184
|
-
|
|
33185
|
-
|
|
33311
|
+
// ==========================================
|
|
33312
|
+
// GERENCIAMENTO DE LISTENERS
|
|
33313
|
+
// ==========================================
|
|
33314
|
+
attachListeners() {
|
|
33315
|
+
if (this.optionsProctoring.captureScreen) {
|
|
33316
|
+
window.addEventListener("blur", this.handleLostFocus);
|
|
33317
|
+
window.addEventListener("focus", this.handleReturnFocus);
|
|
33318
|
+
window.addEventListener("resize", this.handleResize);
|
|
33319
|
+
window.document.addEventListener("copy", this.handleCopy);
|
|
33320
|
+
window.document.addEventListener("cut", this.handleCut);
|
|
33321
|
+
window.document.addEventListener("paste", this.handlePaste);
|
|
33322
|
+
}
|
|
33323
|
+
}
|
|
33324
|
+
detachListeners() {
|
|
33325
|
+
window.removeEventListener("blur", this.handleLostFocus);
|
|
33326
|
+
window.removeEventListener("focus", this.handleReturnFocus);
|
|
33327
|
+
window.removeEventListener("resize", this.handleResize);
|
|
33328
|
+
window.document.removeEventListener("copy", this.handleCopy);
|
|
33329
|
+
window.document.removeEventListener("cut", this.handleCut);
|
|
33330
|
+
window.document.removeEventListener("paste", this.handlePaste);
|
|
33331
|
+
}
|
|
33332
|
+
// private startIdleChecker() {
|
|
33333
|
+
// this.stopIdleChecker(); // Garante que não tenha duplicação
|
|
33334
|
+
// this.idleCheckInterval = setInterval(() => {
|
|
33335
|
+
// const idleTime = Date.now() - this.lastActivityTime;
|
|
33336
|
+
// if (idleTime > this.IDLE_THRESHOLD_MS) {
|
|
33337
|
+
// // Verifica se já não mandamos esse alerta recentemente para não floodar
|
|
33338
|
+
// const lastAlert = this.alerts[this.alerts.length - 1];
|
|
33339
|
+
// // Se o último alerta não foi de inatividade ou foi há muito tempo, cria novo
|
|
33340
|
+
// if (!lastAlert || lastAlert.alert !== AlertCategory.ForbiddenAction || (this.getRelativeTime() - lastAlert.begin > 5000)) {
|
|
33341
|
+
// const msg = "Usuário inativo por muito tempo";
|
|
33342
|
+
// // Assumindo ForbiddenAction ou outra categoria adequada
|
|
33343
|
+
// this.createAlert(AlertCategory.ForbiddenAction, AlertType.System, msg);
|
|
33344
|
+
// this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
|
|
33345
|
+
// status: 'ALERT',
|
|
33346
|
+
// description: msg,
|
|
33347
|
+
// type: 'user_idle'
|
|
33348
|
+
// });
|
|
33349
|
+
// }
|
|
33350
|
+
// }
|
|
33351
|
+
// }, 5000); // Checa a cada 5 segundos
|
|
33352
|
+
// }
|
|
33353
|
+
// private stopIdleChecker() {
|
|
33354
|
+
// if (this.idleCheckInterval) {
|
|
33355
|
+
// clearInterval(this.idleCheckInterval);
|
|
33356
|
+
// this.idleCheckInterval = null;
|
|
33357
|
+
// }
|
|
33358
|
+
// }
|
|
33359
|
+
// 4. BACKGROUND EVENTS (Eventos disparados manualmente)
|
|
33360
|
+
addBackgroundEvent(description, category = 200 /* System */) {
|
|
33361
|
+
this.createAlert(category, 6 /* System */, description);
|
|
33362
|
+
this.onRealtimeAlertCallback && this.onRealtimeAlertCallback({
|
|
33363
|
+
status: "ALERT",
|
|
33364
|
+
description,
|
|
33365
|
+
type: "background_event"
|
|
33366
|
+
});
|
|
33186
33367
|
}
|
|
33187
|
-
|
|
33188
|
-
|
|
33189
|
-
|
|
33190
|
-
|
|
33191
|
-
|
|
33192
|
-
|
|
33193
|
-
|
|
33194
|
-
|
|
33195
|
-
|
|
33196
|
-
|
|
33197
|
-
|
|
33368
|
+
// ==========================================
|
|
33369
|
+
// HELPERS
|
|
33370
|
+
// ==========================================
|
|
33371
|
+
getRelativeTime() {
|
|
33372
|
+
return Date.now() - this.startTime.getTime();
|
|
33373
|
+
}
|
|
33374
|
+
createAlert(category, type, description) {
|
|
33375
|
+
this.alerts.push({
|
|
33376
|
+
begin: this.getRelativeTime(),
|
|
33377
|
+
end: this.getRelativeTime(),
|
|
33378
|
+
// Eventos pontuais começam e terminam no mesmo ms (exceto focus)
|
|
33379
|
+
alert: category,
|
|
33380
|
+
type
|
|
33381
|
+
// description: description // Se sua interface Alert suportar descrição, descomente
|
|
33382
|
+
});
|
|
33198
33383
|
}
|
|
33199
33384
|
addAlert({ alert, type }) {
|
|
33200
33385
|
this.alerts.push({
|
|
@@ -36769,7 +36954,6 @@ var Proctoring = class {
|
|
|
36769
36954
|
noiseLimit: 40
|
|
36770
36955
|
},
|
|
36771
36956
|
imageBehaviourParameters: {
|
|
36772
|
-
frames: 40,
|
|
36773
36957
|
useUploadImage: true,
|
|
36774
36958
|
uploadInterval: 20,
|
|
36775
36959
|
saveVideo: true
|
|
@@ -36987,7 +37171,8 @@ var Proctoring = class {
|
|
|
36987
37171
|
const alertRecorder = new AlertRecorder(
|
|
36988
37172
|
{
|
|
36989
37173
|
onFocusCallback: (response) => this.onFocusAlertRecorderCallback(response),
|
|
36990
|
-
onLostFocusCallback: (response) => this.onLostFocusAlertRecorderCallback(response)
|
|
37174
|
+
onLostFocusCallback: (response) => this.onLostFocusAlertRecorderCallback(response),
|
|
37175
|
+
onRealtimeAlertCallback: (response) => this.onRealtimeAlertsCallback(response)
|
|
36991
37176
|
},
|
|
36992
37177
|
options
|
|
36993
37178
|
);
|
|
@@ -37095,11 +37280,23 @@ Navigator: ${JSON.stringify(_navigator2)}`
|
|
|
37095
37280
|
startResponse.screenStream = this.allRecorders.screenRecorder.screenStream;
|
|
37096
37281
|
}
|
|
37097
37282
|
this.state = "Recording" /* Recording */;
|
|
37098
|
-
|
|
37283
|
+
let verifyFirstFaceIntervalCount = 0;
|
|
37284
|
+
let verifyingFace = false;
|
|
37285
|
+
this.verifyFirstFaceInterval = setInterval(async () => {
|
|
37099
37286
|
if (this.sessionOptions.proctoringType === "REALTIME") {
|
|
37100
|
-
|
|
37287
|
+
if (verifyingFace) return;
|
|
37288
|
+
verifyingFace = true;
|
|
37289
|
+
verifyFirstFaceIntervalCount++;
|
|
37290
|
+
try {
|
|
37291
|
+
var response = await this.backend.verifyFace(this.proctoringId, await this.allRecorders.cameraRecorder.getCurrentImageBase64(), verifyFirstFaceIntervalCount > 5 ? false : true);
|
|
37292
|
+
verifyingFace = false;
|
|
37293
|
+
clearInterval(this.verifyFirstFaceInterval);
|
|
37294
|
+
} catch (error) {
|
|
37295
|
+
verifyingFace = false;
|
|
37296
|
+
return;
|
|
37297
|
+
}
|
|
37101
37298
|
}
|
|
37102
|
-
},
|
|
37299
|
+
}, 1500);
|
|
37103
37300
|
return startResponse;
|
|
37104
37301
|
} catch (error) {
|
|
37105
37302
|
console.log(error);
|
|
@@ -37236,6 +37433,9 @@ Upload Services: ${uploaderServices}`,
|
|
|
37236
37433
|
await this.backend.externalCameraFinish(externalSessionId);
|
|
37237
37434
|
}
|
|
37238
37435
|
}
|
|
37436
|
+
if (this.verifyFirstFaceInterval) {
|
|
37437
|
+
clearInterval(this.verifyFirstFaceInterval);
|
|
37438
|
+
}
|
|
37239
37439
|
this.state = "Stop" /* Stop */;
|
|
37240
37440
|
} catch (error) {
|
|
37241
37441
|
await this.cancel();
|
|
@@ -37570,12 +37770,12 @@ function useProctoring(proctoringOptions, enviromentConfig = "prod") {
|
|
|
37570
37770
|
const photo = new CapturePhoto();
|
|
37571
37771
|
const login = proctoring.login.bind(proctoring);
|
|
37572
37772
|
const originalStart = proctoring.start.bind(proctoring);
|
|
37573
|
-
const start = async (parameters2) => {
|
|
37773
|
+
const start = async (parameters2, videoOptions) => {
|
|
37574
37774
|
const deviceResult = checker.getDeviceCheckResult();
|
|
37575
37775
|
if (deviceResult) {
|
|
37576
37776
|
proctoring.setDeviceCheckData(deviceResult);
|
|
37577
37777
|
}
|
|
37578
|
-
return originalStart(parameters2);
|
|
37778
|
+
return originalStart(parameters2, videoOptions);
|
|
37579
37779
|
};
|
|
37580
37780
|
const finish = proctoring.finish.bind(proctoring);
|
|
37581
37781
|
const pause = proctoring.pause.bind(proctoring);
|
|
@@ -39,7 +39,7 @@ export declare class BackendService {
|
|
|
39
39
|
stopChallenge(challengeId: string, body: any): Promise<any>;
|
|
40
40
|
startRealtimeAlert(body: any): Promise<any>;
|
|
41
41
|
stopRealtimeAlert(body: any): Promise<any>;
|
|
42
|
-
verifyFace(proctoringId: any, faceImage: any): Promise<any>;
|
|
42
|
+
verifyFace(proctoringId: any, faceImage: any, retry: boolean): Promise<any>;
|
|
43
43
|
getServerHour(token: string): Promise<string>;
|
|
44
44
|
private makeRequest;
|
|
45
45
|
makeRequestAxios<R>(data: {
|
|
@@ -24,7 +24,9 @@ export declare enum AlertCategory {
|
|
|
24
24
|
PotentialCamera = 32,
|
|
25
25
|
SpyDeviceDisconnected = 33,
|
|
26
26
|
StopSharingScreen = 34,
|
|
27
|
-
ChangeDevices = 39
|
|
27
|
+
ChangeDevices = 39,
|
|
28
|
+
ForbiddenAction = 100,
|
|
29
|
+
System = 200
|
|
28
30
|
}
|
|
29
31
|
export declare enum FinishRealtimeWarningCategory {
|
|
30
32
|
Face = 0,
|
|
@@ -36,7 +38,8 @@ export declare enum AlertType {
|
|
|
36
38
|
Video = 2,
|
|
37
39
|
Screen = 3,
|
|
38
40
|
Image = 4,
|
|
39
|
-
Environment = 5
|
|
41
|
+
Environment = 5,
|
|
42
|
+
System = 6
|
|
40
43
|
}
|
|
41
44
|
export interface Alert {
|
|
42
45
|
begin: number;
|
|
@@ -6,18 +6,34 @@ export declare class AlertRecorder implements IRecorder {
|
|
|
6
6
|
private startTime;
|
|
7
7
|
private onLostFocusCallback;
|
|
8
8
|
private onFocusCallback;
|
|
9
|
+
private onRealtimeAlertCallback?;
|
|
9
10
|
private optionsProctoring;
|
|
11
|
+
private lastActivityTime;
|
|
12
|
+
private idleCheckInterval;
|
|
13
|
+
private readonly IDLE_THRESHOLD_MS;
|
|
14
|
+
private resizeTimeout;
|
|
10
15
|
constructor(options: {
|
|
11
16
|
onLostFocusCallback: (response: any) => void;
|
|
12
17
|
onFocusCallback: (response: any) => void;
|
|
18
|
+
onRealtimeAlertCallback?: (response: any) => void;
|
|
13
19
|
}, optionsProctoring: ProctoringSessionOptions);
|
|
14
20
|
startRecording(): Promise<void>;
|
|
15
21
|
pauseRecording(): Promise<void>;
|
|
16
22
|
resumeRecording(): Promise<void>;
|
|
17
23
|
stopRecording(): Promise<void>;
|
|
18
24
|
saveOnSession(session: ProctoringSession): Promise<void>;
|
|
19
|
-
private
|
|
20
|
-
private
|
|
25
|
+
private attachListeners;
|
|
26
|
+
private detachListeners;
|
|
27
|
+
private handleLostFocus;
|
|
28
|
+
private handleReturnFocus;
|
|
29
|
+
private handleResize;
|
|
30
|
+
private handleUserActivity;
|
|
31
|
+
addBackgroundEvent(description: string, category?: AlertCategory): void;
|
|
32
|
+
private handleCopy;
|
|
33
|
+
private handleCut;
|
|
34
|
+
private handlePaste;
|
|
35
|
+
private getRelativeTime;
|
|
36
|
+
private createAlert;
|
|
21
37
|
addAlert({ alert, type }: {
|
|
22
38
|
alert: AlertCategory;
|
|
23
39
|
type: AlertType;
|
package/package.json
CHANGED
|
@@ -55,6 +55,7 @@ export declare class Proctoring {
|
|
|
55
55
|
private allRecorders;
|
|
56
56
|
private spyCam;
|
|
57
57
|
appChecker: ExternalCameraChecker;
|
|
58
|
+
private verifyFirstFaceInterval;
|
|
58
59
|
private onStopSharingScreenCallback;
|
|
59
60
|
setOnStopSharingScreenCallback(cb: () => void): void;
|
|
60
61
|
private setOnLostFocusAlertRecorderCallback;
|
|
@@ -3,7 +3,7 @@ import enumarateDevices from "../modules/enumarateDevices";
|
|
|
3
3
|
import { ProctoringContext } from "./proctoring";
|
|
4
4
|
export declare function useProctoring(proctoringOptions: ProctoringContext, enviromentConfig?: string): {
|
|
5
5
|
login: () => Promise<void>;
|
|
6
|
-
start: (parameters: any) => Promise<import("../dtos/StartProctoringResponse").default>;
|
|
6
|
+
start: (parameters: any, videoOptions: any) => Promise<import("../dtos/StartProctoringResponse").default>;
|
|
7
7
|
finish: (options?: import("./proctoring").ProctoringFinisherOptions) => Promise<void>;
|
|
8
8
|
onFocus: (cb: () => void) => Promise<void>;
|
|
9
9
|
onLostFocus: (cb: () => void) => Promise<void>;
|