@newtonschool/react_proctoring_library 0.0.10 → 0.0.13
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/components/ProctorApp.js +16 -21
- package/dist/components/activity-tracker/index.js +1 -0
- package/dist/constants/defaults.js +4 -2
- package/dist/hooks/useWebcamData.js +35 -33
- package/dist/utils/breachUtils.js +22 -4
- package/dist/utils/gpuUtils.js +8 -1
- package/dist/utils/index.js +6 -0
- package/dist/utils/webcamMicrophoneUtils.js +17 -3
- package/package.json +1 -1
|
@@ -27,6 +27,8 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
|
|
|
27
27
|
|
|
28
28
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
29
|
|
|
30
|
+
const isWebcamProcessingReliable = (0, _utils.isGPUAvailable)();
|
|
31
|
+
|
|
30
32
|
const ProctorApp = _ref => {
|
|
31
33
|
let {
|
|
32
34
|
proctoringIdentifier,
|
|
@@ -35,7 +37,8 @@ const ProctorApp = _ref => {
|
|
|
35
37
|
userCount: true,
|
|
36
38
|
tabSwitch: true,
|
|
37
39
|
fullscreenExit: true,
|
|
38
|
-
lookedAway: true
|
|
40
|
+
lookedAway: true,
|
|
41
|
+
isWebcamDataReliable: true
|
|
39
42
|
},
|
|
40
43
|
sendData = () => {},
|
|
41
44
|
shouldSendDataOnBreach = false
|
|
@@ -43,7 +46,6 @@ const ProctorApp = _ref => {
|
|
|
43
46
|
const webcamReference = (0, _react.useRef)(null);
|
|
44
47
|
const canvasReference = (0, _react.useRef)(null);
|
|
45
48
|
const statistics = (0, _react.useRef)(_defaults.INITIAL_STATISTICS);
|
|
46
|
-
const gpuAvailable = (0, _utils.isGPUAvailable)();
|
|
47
49
|
const [audioPermission, setAudioPermission] = (0, _react.useState)(false);
|
|
48
50
|
const [videoPermission, setVideoPermission] = (0, _react.useState)(false);
|
|
49
51
|
const firstFullScreenDone = (0, _react.useRef)(false);
|
|
@@ -52,34 +54,27 @@ const ProctorApp = _ref => {
|
|
|
52
54
|
setFullscreen,
|
|
53
55
|
fullScreenExitCount
|
|
54
56
|
} = (0, _hooks.useFullscreenData)(firstFullScreenDone);
|
|
55
|
-
const [userCount, lookedAwayCount] =
|
|
57
|
+
const [userCount, lookedAwayCount, isWebcamDataReliable] = (0, _useWebcamData.default)(webcamReference, canvasReference);
|
|
56
58
|
const tabSwitchCount = (0, _hooks.useTabSwitchCount)(firstFullScreenDone);
|
|
57
|
-
(0, _react.useEffect)(() => {
|
|
58
|
-
if (!gpuAvailable & shouldSendDataOnBreach) {
|
|
59
|
-
(0, _utils.sendDataOnBreach)(statistics, {
|
|
60
|
-
userCount,
|
|
61
|
-
tabSwitchCount,
|
|
62
|
-
fullScreenExitCount,
|
|
63
|
-
lookedAwayCount
|
|
64
|
-
}, proctoringIdentifier, sendData);
|
|
65
|
-
}
|
|
66
|
-
}, []);
|
|
67
59
|
(0, _react.useEffect)(() => {
|
|
68
60
|
(0, _utils.removeStatsFromLocalStorage)(proctoringIdentifier);
|
|
69
61
|
}, [proctoringIdentifier]);
|
|
70
62
|
(0, _react.useEffect)(() => {
|
|
63
|
+
const currentStats = {
|
|
64
|
+
userCount,
|
|
65
|
+
tabSwitchCount,
|
|
66
|
+
fullScreenExitCount,
|
|
67
|
+
lookedAwayCount,
|
|
68
|
+
isWebcamDataReliable: isWebcamProcessingReliable
|
|
69
|
+
};
|
|
70
|
+
|
|
71
71
|
if (shouldSendDataOnBreach) {
|
|
72
|
-
(0, _utils.sendDataOnBreach)(statistics,
|
|
73
|
-
userCount,
|
|
74
|
-
tabSwitchCount,
|
|
75
|
-
fullScreenExitCount,
|
|
76
|
-
lookedAwayCount
|
|
77
|
-
}, proctoringIdentifier, sendData);
|
|
72
|
+
(0, _utils.sendDataOnBreach)(statistics, currentStats, proctoringIdentifier, sendData, webcamReference);
|
|
78
73
|
}
|
|
79
74
|
|
|
80
|
-
(0, _utils.updateStatistics)(statistics,
|
|
75
|
+
(0, _utils.updateStatistics)(statistics, currentStats);
|
|
81
76
|
(0, _utils.addOrUpdateStatsToLocalStorage)(proctoringIdentifier, statistics.current);
|
|
82
|
-
}, [userCount, tabSwitchCount, fullScreenExitCount, lookedAwayCount, proctoringIdentifier, sendData, shouldSendDataOnBreach]);
|
|
77
|
+
}, [userCount, tabSwitchCount, fullScreenExitCount, lookedAwayCount, isWebcamDataReliable, proctoringIdentifier, sendData, shouldSendDataOnBreach]);
|
|
83
78
|
|
|
84
79
|
if (proctoringIdentifier === undefined) {
|
|
85
80
|
// todo
|
|
@@ -59,6 +59,7 @@ const ActivityTracker = _ref => {
|
|
|
59
59
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactWebcam.default, {
|
|
60
60
|
audio: true,
|
|
61
61
|
muted: true,
|
|
62
|
+
screenshotFormat: "image/jpeg",
|
|
62
63
|
ref: webcamReference,
|
|
63
64
|
onUserMedia: stream => {
|
|
64
65
|
if (!isChrome) {
|
|
@@ -7,6 +7,7 @@ exports.initialValues = exports.gpuTypes = exports.glancePercentageToPass = expo
|
|
|
7
7
|
const initialValues = {
|
|
8
8
|
tabSwitchCount: 0,
|
|
9
9
|
userCount: 0,
|
|
10
|
+
isWebcamDataReliable: true,
|
|
10
11
|
isWatching: true,
|
|
11
12
|
canOpenFullScreen: false,
|
|
12
13
|
fullScreenExitCount: 0,
|
|
@@ -18,7 +19,8 @@ const INITIAL_STATISTICS = {
|
|
|
18
19
|
TAB_SWITCH_COUNT: initialValues.tabSwitchCount,
|
|
19
20
|
FULLSCREEN_EXIT_COUNT: initialValues.fullScreenExitCount,
|
|
20
21
|
LOOKED_AWAY_COUNT: initialValues.lookedAwayCount,
|
|
21
|
-
USER_COUNT_MAX: initialValues.userCount
|
|
22
|
+
USER_COUNT_MAX: initialValues.userCount,
|
|
23
|
+
IS_WEBCAM_DATA_RELIABLE: initialValues.isWebcamDataReliable
|
|
22
24
|
};
|
|
23
25
|
exports.INITIAL_STATISTICS = INITIAL_STATISTICS;
|
|
24
26
|
const bodyPixConfigs = {
|
|
@@ -36,5 +38,5 @@ const glancePercentageToPass = 60;
|
|
|
36
38
|
exports.glancePercentageToPass = glancePercentageToPass;
|
|
37
39
|
const evaluateVideoIntervalInSeconds = 1;
|
|
38
40
|
exports.evaluateVideoIntervalInSeconds = evaluateVideoIntervalInSeconds;
|
|
39
|
-
const gpuTypes = ["apple", "amd", "radeon", "nvidia", "geforce"];
|
|
41
|
+
const gpuTypes = ["intel", "apple", "amd", "radeon", "nvidia", "geforce"];
|
|
40
42
|
exports.gpuTypes = gpuTypes;
|
|
@@ -47,40 +47,42 @@ function useWebcamData(webcamReference, canvasReference) {
|
|
|
47
47
|
const [isWatching, setIsWatching] = (0, _react.useState)(_defaults.initialValues.isWatching);
|
|
48
48
|
const [lookedAwayCount, setLookedAwayCount] = (0, _react.useState)(_defaults.initialValues.lookedAwayCount);
|
|
49
49
|
(0, _react.useEffect)(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
50
|
+
if ((0, _utils.isGPUAvailable)()) {
|
|
51
|
+
const loadBodyPixModel = async () => {
|
|
52
|
+
try {
|
|
53
|
+
const network = await bodyPix.load();
|
|
54
|
+
setInterval(async () => {
|
|
55
|
+
if ((0, _utils.isWebcamVideoValid)(webcamReference)) {
|
|
56
|
+
var _users$length;
|
|
57
|
+
|
|
58
|
+
const video = webcamReference.current.video;
|
|
59
|
+
const {
|
|
60
|
+
videoWidth,
|
|
61
|
+
videoHeight
|
|
62
|
+
} = video;
|
|
63
|
+
video.width = videoWidth;
|
|
64
|
+
video.height = videoHeight;
|
|
65
|
+
canvasReference.current.width = videoWidth;
|
|
66
|
+
canvasReference.current.height = videoHeight;
|
|
67
|
+
const users = await getUsers(network, video);
|
|
68
|
+
const count = (_users$length = users === null || users === void 0 ? void 0 : users.length) !== null && _users$length !== void 0 ? _users$length : 0;
|
|
69
|
+
setUserCount(count);
|
|
70
|
+
|
|
71
|
+
if (count) {
|
|
72
|
+
setIsWatching(getIsWatching(network, video));
|
|
73
|
+
} else {
|
|
74
|
+
setIsWatching(false);
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
}, _defaults.evaluateVideoIntervalInSeconds * 1000);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.log("Error Trace:", err);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
loadBodyPixModel();
|
|
85
|
+
}
|
|
84
86
|
}, [webcamReference, canvasReference]);
|
|
85
87
|
(0, _react.useEffect)(() => {
|
|
86
88
|
if (!isWatching) {
|
|
@@ -5,30 +5,46 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.sendDataOnBreach = void 0;
|
|
7
7
|
|
|
8
|
+
var _ = require(".");
|
|
9
|
+
|
|
8
10
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
9
11
|
|
|
10
12
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
11
13
|
|
|
12
14
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
13
15
|
|
|
14
|
-
const sendDataOnBreach = (statistics, currentData, proctoringIdentifier, sendData) => {
|
|
16
|
+
const sendDataOnBreach = (statistics, currentData, proctoringIdentifier, sendData, webcamReference) => {
|
|
15
17
|
const {
|
|
16
18
|
userCount,
|
|
17
19
|
tabSwitchCount,
|
|
18
20
|
fullScreenExitCount,
|
|
19
|
-
lookedAwayCount
|
|
21
|
+
lookedAwayCount,
|
|
22
|
+
isWebcamDataReliable
|
|
20
23
|
} = currentData;
|
|
21
24
|
const timestamp = Date.now();
|
|
22
25
|
const data = statistics.current;
|
|
23
26
|
|
|
27
|
+
if (data.IS_WEBCAM_DATA_RELIABLE !== isWebcamDataReliable) {
|
|
28
|
+
sendData({
|
|
29
|
+
proctoringIdentifier,
|
|
30
|
+
breach: "IS_WEBCAM_DATA_RELIABLE",
|
|
31
|
+
timestamp,
|
|
32
|
+
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
33
|
+
IS_WEBCAM_DATA_RELIABLE: isWebcamDataReliable
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
if (data.USER_COUNT_MAX < userCount) {
|
|
39
|
+
const webcamSnapshot = (0, _.captureWebcamSnapshot)(webcamReference);
|
|
25
40
|
sendData({
|
|
26
41
|
proctoringIdentifier,
|
|
27
42
|
breach: "USER_COUNT_MAX",
|
|
28
43
|
timestamp,
|
|
29
44
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
30
45
|
USER_COUNT_MAX: userCount
|
|
31
|
-
})
|
|
46
|
+
}),
|
|
47
|
+
webcamSnapshot
|
|
32
48
|
});
|
|
33
49
|
}
|
|
34
50
|
|
|
@@ -55,13 +71,15 @@ const sendDataOnBreach = (statistics, currentData, proctoringIdentifier, sendDat
|
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
if (data.LOOKED_AWAY_COUNT !== lookedAwayCount) {
|
|
74
|
+
const webcamSnapshot = (0, _.captureWebcamSnapshot)(webcamReference);
|
|
58
75
|
sendData({
|
|
59
76
|
proctoringIdentifier,
|
|
60
77
|
breach: "LOOKED_AWAY_COUNT",
|
|
61
78
|
timestamp,
|
|
62
79
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
63
80
|
LOOKED_AWAY_COUNT: lookedAwayCount
|
|
64
|
-
})
|
|
81
|
+
}),
|
|
82
|
+
webcamSnapshot
|
|
65
83
|
});
|
|
66
84
|
}
|
|
67
85
|
};
|
package/dist/utils/gpuUtils.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isGPUAvailable = void 0;
|
|
7
|
+
|
|
3
8
|
require("core-js/modules/web.dom-collections.iterator.js");
|
|
4
9
|
|
|
5
10
|
require("core-js/modules/es.array.includes.js");
|
|
@@ -19,4 +24,6 @@ const isGPUAvailable = () => {
|
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
return false;
|
|
22
|
-
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
exports.isGPUAvailable = isGPUAvailable;
|
package/dist/utils/index.js
CHANGED
|
@@ -9,6 +9,12 @@ Object.defineProperty(exports, "addOrUpdateStatsToLocalStorage", {
|
|
|
9
9
|
return _localStorageUtils.addOrUpdateStatsToLocalStorage;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
+
Object.defineProperty(exports, "captureWebcamSnapshot", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function get() {
|
|
15
|
+
return _webcamMicrophoneUtils.captureWebcamSnapshot;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
12
18
|
Object.defineProperty(exports, "getAudioPermission", {
|
|
13
19
|
enumerable: true,
|
|
14
20
|
get: function get() {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.updateVideoPermissions = exports.updateStatistics = exports.updateAudioPermissions = exports.isWebcamVideoValid = exports.getVideoPermissionQuery = exports.getVideoPermission = exports.getGlancePercentage = exports.getAudioVideoPermission = exports.getAudioPermissionQuery = exports.getAudioPermission = void 0;
|
|
6
|
+
exports.updateVideoPermissions = exports.updateStatistics = exports.updateAudioPermissions = exports.isWebcamVideoValid = exports.getVideoPermissionQuery = exports.getVideoPermission = exports.getGlancePercentage = exports.getAudioVideoPermission = exports.getAudioPermissionQuery = exports.getAudioPermission = exports.captureWebcamSnapshot = void 0;
|
|
7
7
|
|
|
8
8
|
var _ = require(".");
|
|
9
9
|
|
|
@@ -11,11 +11,19 @@ const isWebcamVideoValid = webcamReference => webcamReference !== null && webcam
|
|
|
11
11
|
|
|
12
12
|
exports.isWebcamVideoValid = isWebcamVideoValid;
|
|
13
13
|
|
|
14
|
-
const updateStatistics = (statistics,
|
|
14
|
+
const updateStatistics = (statistics, currentStats) => {
|
|
15
|
+
const {
|
|
16
|
+
tabSwitchCount,
|
|
17
|
+
fullScreenExitCount,
|
|
18
|
+
lookedAwayCount,
|
|
19
|
+
userCount,
|
|
20
|
+
isWebcamDataReliable
|
|
21
|
+
} = currentStats;
|
|
15
22
|
statistics.current.TAB_SWITCH_COUNT = tabSwitchCount;
|
|
16
23
|
statistics.current.FULLSCREEN_EXIT_COUNT = fullScreenExitCount;
|
|
17
24
|
statistics.current.LOOKED_AWAY_COUNT = lookedAwayCount;
|
|
18
25
|
statistics.current.USER_COUNT_MAX = Math.max(userCount, statistics.current.USER_COUNT_MAX);
|
|
26
|
+
statistics.current.IS_WEBCAM_DATA_RELIABLE = isWebcamDataReliable;
|
|
19
27
|
};
|
|
20
28
|
|
|
21
29
|
exports.updateStatistics = updateStatistics;
|
|
@@ -112,4 +120,10 @@ const getAudioPermissionQuery = () => navigator.permissions.query({
|
|
|
112
120
|
name: "microphone"
|
|
113
121
|
});
|
|
114
122
|
|
|
115
|
-
exports.getAudioPermissionQuery = getAudioPermissionQuery;
|
|
123
|
+
exports.getAudioPermissionQuery = getAudioPermissionQuery;
|
|
124
|
+
|
|
125
|
+
const captureWebcamSnapshot = webcamReference => {
|
|
126
|
+
return webcamReference.current.getScreenshot();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
exports.captureWebcamSnapshot = captureWebcamSnapshot;
|