@rcnr/lockdown 1.2.0 → 1.3.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/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +24 -1
- package/dist/index.mjs +24 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -4,7 +4,7 @@ interface Violation {
|
|
|
4
4
|
timestamp: number;
|
|
5
5
|
}
|
|
6
6
|
/** All violation types the lockdown hook can detect. */
|
|
7
|
-
type ViolationType = "fullscreen_exit" | "tab_switch" | "window_blur" | "paste_attempt" | "copy_attempt" | "cut_attempt" | "drop_attempt" | "devtools_attempt" | "extension_detected";
|
|
7
|
+
type ViolationType = "fullscreen_exit" | "tab_switch" | "window_blur" | "paste_attempt" | "copy_attempt" | "cut_attempt" | "drop_attempt" | "devtools_attempt" | "extension_detected" | "voice_input" | "pip_detected";
|
|
8
8
|
/** Violations that trigger instant auto-submit (cheating attempts). */
|
|
9
9
|
declare const INSTANT_SUBMIT_VIOLATIONS: Set<ViolationType>;
|
|
10
10
|
/** Configuration for the lockdown hook. */
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ interface Violation {
|
|
|
4
4
|
timestamp: number;
|
|
5
5
|
}
|
|
6
6
|
/** All violation types the lockdown hook can detect. */
|
|
7
|
-
type ViolationType = "fullscreen_exit" | "tab_switch" | "window_blur" | "paste_attempt" | "copy_attempt" | "cut_attempt" | "drop_attempt" | "devtools_attempt" | "extension_detected";
|
|
7
|
+
type ViolationType = "fullscreen_exit" | "tab_switch" | "window_blur" | "paste_attempt" | "copy_attempt" | "cut_attempt" | "drop_attempt" | "devtools_attempt" | "extension_detected" | "voice_input" | "pip_detected";
|
|
8
8
|
/** Violations that trigger instant auto-submit (cheating attempts). */
|
|
9
9
|
declare const INSTANT_SUBMIT_VIOLATIONS: Set<ViolationType>;
|
|
10
10
|
/** Configuration for the lockdown hook. */
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,9 @@ var INSTANT_SUBMIT_VIOLATIONS = /* @__PURE__ */ new Set([
|
|
|
35
35
|
"cut_attempt",
|
|
36
36
|
"drop_attempt",
|
|
37
37
|
"devtools_attempt",
|
|
38
|
-
"extension_detected"
|
|
38
|
+
"extension_detected",
|
|
39
|
+
"voice_input",
|
|
40
|
+
"pip_detected"
|
|
39
41
|
]);
|
|
40
42
|
|
|
41
43
|
// src/useLockdown.ts
|
|
@@ -268,6 +270,10 @@ function useLockdown({
|
|
|
268
270
|
e.preventDefault();
|
|
269
271
|
return;
|
|
270
272
|
}
|
|
273
|
+
if (modKey && (e.key.toLowerCase() === "f" || e.key.toLowerCase() === "h")) {
|
|
274
|
+
e.preventDefault();
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
271
277
|
if (e.altKey && e.key === "Tab") {
|
|
272
278
|
e.preventDefault();
|
|
273
279
|
return;
|
|
@@ -280,6 +286,19 @@ function useLockdown({
|
|
|
280
286
|
function handleContextMenu(e) {
|
|
281
287
|
e.preventDefault();
|
|
282
288
|
}
|
|
289
|
+
function handleBeforeInput(e) {
|
|
290
|
+
const inputEvent = e;
|
|
291
|
+
const type = inputEvent.inputType;
|
|
292
|
+
if (type === "insertFromDictation" || type === "insertFromVoice" || // Some browsers report dictation as insertReplacementText
|
|
293
|
+
// but only flag it if it inserts a lot of text at once (>50 chars)
|
|
294
|
+
type === "insertReplacementText" && inputEvent.data && inputEvent.data.length > 50) {
|
|
295
|
+
e.preventDefault();
|
|
296
|
+
addViolation("voice_input");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function handlePipEnter() {
|
|
300
|
+
addViolation("pip_detected");
|
|
301
|
+
}
|
|
283
302
|
function handleFocus() {
|
|
284
303
|
if (countdownIntervalRef.current) {
|
|
285
304
|
clearCountdown();
|
|
@@ -298,6 +317,8 @@ function useLockdown({
|
|
|
298
317
|
document.addEventListener("dragover", handleDragOver);
|
|
299
318
|
document.addEventListener("keydown", handleKeydown);
|
|
300
319
|
document.addEventListener("contextmenu", handleContextMenu);
|
|
320
|
+
document.addEventListener("beforeinput", handleBeforeInput);
|
|
321
|
+
document.addEventListener("enterpictureinpicture", handlePipEnter, true);
|
|
301
322
|
return () => {
|
|
302
323
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
303
324
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
@@ -312,6 +333,8 @@ function useLockdown({
|
|
|
312
333
|
document.removeEventListener("dragover", handleDragOver);
|
|
313
334
|
document.removeEventListener("keydown", handleKeydown);
|
|
314
335
|
document.removeEventListener("contextmenu", handleContextMenu);
|
|
336
|
+
document.removeEventListener("beforeinput", handleBeforeInput);
|
|
337
|
+
document.removeEventListener("enterpictureinpicture", handlePipEnter, true);
|
|
315
338
|
};
|
|
316
339
|
}, [enabled, addViolation, startCountdown, clearCountdown]);
|
|
317
340
|
(0, import_react.useEffect)(() => {
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,9 @@ var INSTANT_SUBMIT_VIOLATIONS = /* @__PURE__ */ new Set([
|
|
|
8
8
|
"cut_attempt",
|
|
9
9
|
"drop_attempt",
|
|
10
10
|
"devtools_attempt",
|
|
11
|
-
"extension_detected"
|
|
11
|
+
"extension_detected",
|
|
12
|
+
"voice_input",
|
|
13
|
+
"pip_detected"
|
|
12
14
|
]);
|
|
13
15
|
|
|
14
16
|
// src/useLockdown.ts
|
|
@@ -241,6 +243,10 @@ function useLockdown({
|
|
|
241
243
|
e.preventDefault();
|
|
242
244
|
return;
|
|
243
245
|
}
|
|
246
|
+
if (modKey && (e.key.toLowerCase() === "f" || e.key.toLowerCase() === "h")) {
|
|
247
|
+
e.preventDefault();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
244
250
|
if (e.altKey && e.key === "Tab") {
|
|
245
251
|
e.preventDefault();
|
|
246
252
|
return;
|
|
@@ -253,6 +259,19 @@ function useLockdown({
|
|
|
253
259
|
function handleContextMenu(e) {
|
|
254
260
|
e.preventDefault();
|
|
255
261
|
}
|
|
262
|
+
function handleBeforeInput(e) {
|
|
263
|
+
const inputEvent = e;
|
|
264
|
+
const type = inputEvent.inputType;
|
|
265
|
+
if (type === "insertFromDictation" || type === "insertFromVoice" || // Some browsers report dictation as insertReplacementText
|
|
266
|
+
// but only flag it if it inserts a lot of text at once (>50 chars)
|
|
267
|
+
type === "insertReplacementText" && inputEvent.data && inputEvent.data.length > 50) {
|
|
268
|
+
e.preventDefault();
|
|
269
|
+
addViolation("voice_input");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function handlePipEnter() {
|
|
273
|
+
addViolation("pip_detected");
|
|
274
|
+
}
|
|
256
275
|
function handleFocus() {
|
|
257
276
|
if (countdownIntervalRef.current) {
|
|
258
277
|
clearCountdown();
|
|
@@ -271,6 +290,8 @@ function useLockdown({
|
|
|
271
290
|
document.addEventListener("dragover", handleDragOver);
|
|
272
291
|
document.addEventListener("keydown", handleKeydown);
|
|
273
292
|
document.addEventListener("contextmenu", handleContextMenu);
|
|
293
|
+
document.addEventListener("beforeinput", handleBeforeInput);
|
|
294
|
+
document.addEventListener("enterpictureinpicture", handlePipEnter, true);
|
|
274
295
|
return () => {
|
|
275
296
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
276
297
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
@@ -285,6 +306,8 @@ function useLockdown({
|
|
|
285
306
|
document.removeEventListener("dragover", handleDragOver);
|
|
286
307
|
document.removeEventListener("keydown", handleKeydown);
|
|
287
308
|
document.removeEventListener("contextmenu", handleContextMenu);
|
|
309
|
+
document.removeEventListener("beforeinput", handleBeforeInput);
|
|
310
|
+
document.removeEventListener("enterpictureinpicture", handlePipEnter, true);
|
|
288
311
|
};
|
|
289
312
|
}, [enabled, addViolation, startCountdown, clearCountdown]);
|
|
290
313
|
useEffect(() => {
|