@newtonschool/react_proctoring_library 0.0.12 → 0.0.15
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 +94 -30
- package/dist/components/activity-tracker/index.js +12 -3
- package/dist/components/permissions/index.js +13 -5
- package/dist/components/permissions/permission-body.js +7 -2
- package/dist/constants/defaults.js +1 -1
- package/dist/constants/text.js +6 -2
- package/dist/hooks/useWebcamData.js +2 -8
- package/dist/index.js +1 -9
- package/dist/utils/breachUtils.js +18 -23
- package/dist/utils/index.js +6 -0
- package/dist/utils/webcamMicrophoneUtils.js +93 -3
- package/package.json +2 -1
|
@@ -7,6 +7,8 @@ exports.default = exports.ProctorApp = void 0;
|
|
|
7
7
|
|
|
8
8
|
require("core-js/modules/web.dom-collections.iterator.js");
|
|
9
9
|
|
|
10
|
+
require("core-js/modules/es.promise.js");
|
|
11
|
+
|
|
10
12
|
var _react = _interopRequireWildcard(require("react"));
|
|
11
13
|
|
|
12
14
|
var _ = require(".");
|
|
@@ -21,73 +23,135 @@ var _permissions = require("./permissions");
|
|
|
21
23
|
|
|
22
24
|
var _useWebcamData = _interopRequireDefault(require("../hooks/useWebcamData"));
|
|
23
25
|
|
|
26
|
+
var _breachUtils = require("../utils/breachUtils");
|
|
27
|
+
|
|
28
|
+
var _webcamMicrophoneUtils = require("../utils/webcamMicrophoneUtils");
|
|
29
|
+
|
|
24
30
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
31
|
|
|
26
32
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
27
33
|
|
|
28
34
|
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
35
|
|
|
36
|
+
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; }
|
|
37
|
+
|
|
38
|
+
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; }
|
|
39
|
+
|
|
40
|
+
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; }
|
|
41
|
+
|
|
42
|
+
const isWebcamProcessingReliable = (0, _utils.isGPUAvailable)();
|
|
43
|
+
|
|
30
44
|
const ProctorApp = _ref => {
|
|
31
45
|
let {
|
|
32
46
|
proctoringIdentifier,
|
|
33
47
|
children,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
lookedAway: true,
|
|
39
|
-
isWebcamDataReliable: true
|
|
40
|
-
},
|
|
41
|
-
sendData = () => {},
|
|
42
|
-
shouldSendDataOnBreach = false
|
|
48
|
+
config,
|
|
49
|
+
getProctorParamValues = () => {},
|
|
50
|
+
getWebcamSnapshot = () => {},
|
|
51
|
+
getScreengrab = () => {}
|
|
43
52
|
} = _ref;
|
|
44
53
|
const webcamReference = (0, _react.useRef)(null);
|
|
45
54
|
const canvasReference = (0, _react.useRef)(null);
|
|
55
|
+
const screenshareReference = (0, _react.useRef)(null);
|
|
46
56
|
const statistics = (0, _react.useRef)(_defaults.INITIAL_STATISTICS);
|
|
47
|
-
|
|
48
|
-
const
|
|
57
|
+
|
|
58
|
+
const proctorParams = _objectSpread(_objectSpread({}, {
|
|
59
|
+
people: true,
|
|
60
|
+
tabSwitch: true,
|
|
61
|
+
fullscreenExit: true,
|
|
62
|
+
lookedAway: true
|
|
63
|
+
}), config.proctorParams);
|
|
64
|
+
|
|
65
|
+
const {
|
|
66
|
+
recurring = false,
|
|
67
|
+
recurringFetchInterval = 0
|
|
68
|
+
} = config;
|
|
69
|
+
const [audioPermission, setAudioPermission] = (0, _react.useState)();
|
|
70
|
+
const [videoPermission, setVideoPermission] = (0, _react.useState)();
|
|
71
|
+
const [screensharePermission, setScreensharePermission] = (0, _react.useState)();
|
|
49
72
|
const firstFullScreenDone = (0, _react.useRef)(false);
|
|
73
|
+
const recurringFetchIntervalRef = (0, _react.useRef)(null);
|
|
74
|
+
const sendScreengrab = (0, _react.useCallback)(async function () {
|
|
75
|
+
let isBreach = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
76
|
+
let breachData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
77
|
+
const screenshot = await (0, _webcamMicrophoneUtils.captureScreenshot)();
|
|
78
|
+
getScreengrab(proctoringIdentifier, screenshot, isBreach, breachData.breachedParam);
|
|
79
|
+
}, [getScreengrab, proctoringIdentifier]);
|
|
80
|
+
(0, _react.useEffect)(() => {
|
|
81
|
+
if (recurring) {
|
|
82
|
+
recurringFetchIntervalRef.current = setInterval(() => {
|
|
83
|
+
getProctorParamValues(proctoringIdentifier, statistics.current, false);
|
|
84
|
+
const webcamSnapshot = (0, _utils.captureWebcamSnapshot)(webcamReference);
|
|
85
|
+
|
|
86
|
+
if (webcamReference) {
|
|
87
|
+
getWebcamSnapshot(proctoringIdentifier, webcamSnapshot, false);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
sendScreengrab();
|
|
91
|
+
}, recurringFetchInterval);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
clearInterval(recurringFetchIntervalRef.current);
|
|
96
|
+
};
|
|
97
|
+
}, [recurring, recurringFetchInterval, proctoringIdentifier, getWebcamSnapshot, getProctorParamValues, sendScreengrab]);
|
|
50
98
|
const {
|
|
51
99
|
isFullscreen,
|
|
52
100
|
setFullscreen,
|
|
53
101
|
fullScreenExitCount
|
|
54
102
|
} = (0, _hooks.useFullscreenData)(firstFullScreenDone);
|
|
55
|
-
const [userCount, lookedAwayCount
|
|
103
|
+
const [userCount, lookedAwayCount] = (0, _useWebcamData.default)(webcamReference, canvasReference);
|
|
56
104
|
const tabSwitchCount = (0, _hooks.useTabSwitchCount)(firstFullScreenDone);
|
|
57
105
|
(0, _react.useEffect)(() => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
106
|
+
const currentStats = {
|
|
107
|
+
userCount,
|
|
108
|
+
tabSwitchCount,
|
|
109
|
+
fullScreenExitCount,
|
|
110
|
+
lookedAwayCount,
|
|
111
|
+
isWebcamDataReliable: isWebcamProcessingReliable
|
|
112
|
+
};
|
|
113
|
+
const breachData = (0, _breachUtils.getDataOnBreach)(statistics, currentStats);
|
|
114
|
+
|
|
115
|
+
if (breachData) {
|
|
116
|
+
getProctorParamValues(breachData.proctoringIdentifier, breachData.data, true, breachData.breachedParam);
|
|
117
|
+
|
|
118
|
+
if (breachData.breachedParam === "LOOKED_AWAY_COUNT" || breachData.breachedParam === "USER_COUNT_MAX") {
|
|
119
|
+
const webcamSnapshot = (0, _utils.captureWebcamSnapshot)(webcamReference);
|
|
120
|
+
|
|
121
|
+
if (webcamSnapshot) {
|
|
122
|
+
getWebcamSnapshot(proctoringIdentifier, webcamSnapshot, true, breachData.breachedParam);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
sendScreengrab(true, breachData);
|
|
126
|
+
}
|
|
69
127
|
}
|
|
70
128
|
|
|
71
|
-
(0, _utils.updateStatistics)(statistics,
|
|
72
|
-
|
|
73
|
-
|
|
129
|
+
(0, _utils.updateStatistics)(statistics, currentStats);
|
|
130
|
+
}, [userCount, tabSwitchCount, fullScreenExitCount, lookedAwayCount, getProctorParamValues, getWebcamSnapshot, sendScreengrab, proctoringIdentifier]);
|
|
131
|
+
const updateScreensharePermission = (0, _react.useCallback)(() => {
|
|
132
|
+
(0, _webcamMicrophoneUtils.setupScreensharePermission)(setScreensharePermission, screenshareReference);
|
|
133
|
+
}, []);
|
|
74
134
|
|
|
75
135
|
if (proctoringIdentifier === undefined) {
|
|
76
136
|
// todo
|
|
77
137
|
return;
|
|
78
138
|
}
|
|
79
139
|
|
|
80
|
-
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_permissions.Permission, {
|
|
140
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isFullscreen && audioPermission && videoPermission && screensharePermission && children, /*#__PURE__*/_react.default.createElement(_permissions.Permission, {
|
|
81
141
|
isFullscreen: isFullscreen,
|
|
82
142
|
audioPermisison: audioPermission,
|
|
83
143
|
videoPermission: videoPermission,
|
|
84
|
-
setFullscreen: setFullscreen
|
|
144
|
+
setFullscreen: setFullscreen,
|
|
145
|
+
screensharePermission: screensharePermission,
|
|
146
|
+
updateScreensharePermission: updateScreensharePermission
|
|
85
147
|
}), /*#__PURE__*/_react.default.createElement(_.ActivityTracker, {
|
|
86
148
|
setAudioPermission: setAudioPermission,
|
|
87
149
|
setVideoPermission: setVideoPermission,
|
|
88
150
|
webcamReference: webcamReference,
|
|
89
|
-
canvasReference: canvasReference
|
|
90
|
-
|
|
151
|
+
canvasReference: canvasReference,
|
|
152
|
+
screenshareReference: screenshareReference,
|
|
153
|
+
updateScreensharePermission: updateScreensharePermission
|
|
154
|
+
}));
|
|
91
155
|
};
|
|
92
156
|
|
|
93
157
|
exports.ProctorApp = ProctorApp;
|
|
@@ -34,12 +34,15 @@ const ActivityTracker = _ref => {
|
|
|
34
34
|
webcamReference,
|
|
35
35
|
canvasReference,
|
|
36
36
|
setAudioPermission,
|
|
37
|
-
setVideoPermission
|
|
37
|
+
setVideoPermission,
|
|
38
|
+
updateScreensharePermission,
|
|
39
|
+
screenshareReference
|
|
38
40
|
} = _ref;
|
|
39
41
|
(0, _react.useEffect)(() => {
|
|
40
42
|
if (isChrome) {
|
|
41
43
|
(0, _webcamMicrophoneUtils.updateVideoPermissions)(setVideoPermission);
|
|
42
44
|
(0, _webcamMicrophoneUtils.updateAudioPermissions)(setAudioPermission);
|
|
45
|
+
updateScreensharePermission();
|
|
43
46
|
(0, _webcamMicrophoneUtils.getVideoPermissionQuery)().then(status => {
|
|
44
47
|
status.onchange = evt => {
|
|
45
48
|
(0, _webcamMicrophoneUtils.updateVideoPermissions)(setVideoPermission);
|
|
@@ -55,10 +58,11 @@ const ActivityTracker = _ref => {
|
|
|
55
58
|
(0, _webcamMicrophoneUtils.updateAudioPermissions)("Audio Permission", err);
|
|
56
59
|
});
|
|
57
60
|
}
|
|
58
|
-
}, [setVideoPermission, setAudioPermission]);
|
|
61
|
+
}, [setVideoPermission, setAudioPermission, updateScreensharePermission]);
|
|
59
62
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactWebcam.default, {
|
|
60
63
|
audio: true,
|
|
61
64
|
muted: true,
|
|
65
|
+
screenshotFormat: "image/jpeg",
|
|
62
66
|
ref: webcamReference,
|
|
63
67
|
onUserMedia: stream => {
|
|
64
68
|
if (!isChrome) {
|
|
@@ -136,7 +140,12 @@ const ActivityTracker = _ref => {
|
|
|
136
140
|
className: "captured-video-canvas"
|
|
137
141
|
}), /*#__PURE__*/_react.default.createElement("canvas", {
|
|
138
142
|
ref: canvasReference,
|
|
139
|
-
className: "captured-video-canvas"
|
|
143
|
+
className: "captured-video-canvas",
|
|
144
|
+
id: "wc-ref"
|
|
145
|
+
}), /*#__PURE__*/_react.default.createElement("video", {
|
|
146
|
+
ref: screenshareReference,
|
|
147
|
+
className: "captured-video-canvas",
|
|
148
|
+
id: "ss-ref"
|
|
140
149
|
}));
|
|
141
150
|
};
|
|
142
151
|
|
|
@@ -30,9 +30,12 @@ const Permission = _ref => {
|
|
|
30
30
|
isFullscreen,
|
|
31
31
|
audioPermisison,
|
|
32
32
|
videoPermission,
|
|
33
|
-
setFullscreen
|
|
33
|
+
setFullscreen,
|
|
34
|
+
screensharePermission,
|
|
35
|
+
trackScreenshare,
|
|
36
|
+
updateScreensharePermission
|
|
34
37
|
} = _ref;
|
|
35
|
-
const showPermissionModal =
|
|
38
|
+
const showPermissionModal = isFullscreen === false || audioPermisison === false || videoPermission === false || trackScreenshare && screensharePermission === false;
|
|
36
39
|
return /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal, {
|
|
37
40
|
show: showPermissionModal,
|
|
38
41
|
size: "lg",
|
|
@@ -41,7 +44,7 @@ const Permission = _ref => {
|
|
|
41
44
|
centered: true
|
|
42
45
|
}, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Header, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Title, null, text.PERMISSION_TITLE)), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Body, {
|
|
43
46
|
className: "font-medium"
|
|
44
|
-
}, /*#__PURE__*/_react.default.createElement(
|
|
47
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
45
48
|
style: {
|
|
46
49
|
borderRadius: "20px"
|
|
47
50
|
}
|
|
@@ -58,8 +61,13 @@ const Permission = _ref => {
|
|
|
58
61
|
}), text.VIDEO_UNSUPPORTED_IN_BROWSER)), /*#__PURE__*/_react.default.createElement(_permissionBody.PermissionBody, {
|
|
59
62
|
showFullscreenText: !isFullscreen,
|
|
60
63
|
showAudioPermissionText: !audioPermisison,
|
|
61
|
-
showVideoPermissionText: !videoPermission
|
|
62
|
-
|
|
64
|
+
showVideoPermissionText: !videoPermission,
|
|
65
|
+
showScreensharePermission: !screensharePermission && trackScreenshare
|
|
66
|
+
})), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Footer, null, !screensharePermission && /*#__PURE__*/_react.default.createElement(_reactBootstrap.Button, {
|
|
67
|
+
onClick: () => {
|
|
68
|
+
updateScreensharePermission();
|
|
69
|
+
}
|
|
70
|
+
}, text.ALLOW_SCREENSHARE), !isFullscreen && /*#__PURE__*/_react.default.createElement(_reactBootstrap.Button, {
|
|
63
71
|
variant: "primary",
|
|
64
72
|
onClick: () => {
|
|
65
73
|
setFullscreen();
|
|
@@ -25,11 +25,16 @@ const PermissionBody = _ref => {
|
|
|
25
25
|
let {
|
|
26
26
|
showFullscreenText,
|
|
27
27
|
showAudioPermissionText,
|
|
28
|
-
showVideoPermissionText
|
|
28
|
+
showVideoPermissionText,
|
|
29
|
+
showScreensharePermission
|
|
29
30
|
} = _ref;
|
|
30
31
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
|
|
31
32
|
className: "mb-2"
|
|
32
|
-
}, text.PERMISSION_GENERIC),
|
|
33
|
+
}, text.PERMISSION_GENERIC), showScreensharePermission && /*#__PURE__*/_react.default.createElement("div", {
|
|
34
|
+
className: "mb-2"
|
|
35
|
+
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
36
|
+
className: "pr-2 font-weight-bold"
|
|
37
|
+
}, "Screenshare:"), text.PERMISSION_SCREENSHARE), showAudioPermissionText && showVideoPermissionText ? /*#__PURE__*/_react.default.createElement("div", {
|
|
33
38
|
className: "mb-2"
|
|
34
39
|
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
35
40
|
className: "pr-2 font-weight-bold"
|
|
@@ -38,5 +38,5 @@ const glancePercentageToPass = 60;
|
|
|
38
38
|
exports.glancePercentageToPass = glancePercentageToPass;
|
|
39
39
|
const evaluateVideoIntervalInSeconds = 1;
|
|
40
40
|
exports.evaluateVideoIntervalInSeconds = evaluateVideoIntervalInSeconds;
|
|
41
|
-
const gpuTypes = ["apple", "amd", "radeon", "nvidia", "geforce"];
|
|
41
|
+
const gpuTypes = ["intel", "apple", "amd", "radeon", "nvidia", "geforce"];
|
|
42
42
|
exports.gpuTypes = gpuTypes;
|
package/dist/constants/text.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.WATCHING_SCREEN = exports.VIDEO_UNSUPPORTED_IN_BROWSER = exports.USER_COUNT_LABEL = exports.REQUEST_VIDEO_AUDIO_PERMISSIONS_HEADING = exports.REQUEST_VIDEO_AUDIO_PERMISSIONS_DESC = exports.REQUEST_PERMISSION = exports.PERMISSION_VIDEO = exports.PERMISSION_TITLE = exports.PERMISSION_GENERIC = exports.PERMISSION_FULLSCREEN = exports.PERMISSION_AUDIO_VIDEO = exports.PERMISSION_AUDIO = exports.NO_CAMERA_AVAILABLE = exports.NO_AUDIO_DEVICE_AVAILABLE = exports.NOT_WATCHING_SCREEN = exports.MESSAGE = exports.FULLSCREEN_ERROR_MESSAGE = exports.DENY_FULLSCREEN = exports.CAMERA_UNAVAILABLE_INSECURE_CONN = exports.BROWSER_BLOCKED_PERMISSION_RESOLVED_RECHECK = exports.BROWSER_BLOCKED_PERMISSION_NEXT_STEP = exports.BROWSER_BLOCKED_PERMISSION_DIRECTION = exports.BROWSER_BLOCKED_PERMISSION_DIALOG = exports.BROWSER_BLOCKED_PERMISSION = exports.ALLOW_FULLSCREEN = void 0;
|
|
6
|
+
exports.WATCHING_SCREEN = exports.VIDEO_UNSUPPORTED_IN_BROWSER = exports.USER_COUNT_LABEL = exports.REQUEST_VIDEO_AUDIO_PERMISSIONS_HEADING = exports.REQUEST_VIDEO_AUDIO_PERMISSIONS_DESC = exports.REQUEST_PERMISSION = exports.PERMISSION_VIDEO = exports.PERMISSION_TITLE = exports.PERMISSION_SCREENSHARE = exports.PERMISSION_GENERIC = exports.PERMISSION_FULLSCREEN = exports.PERMISSION_AUDIO_VIDEO = exports.PERMISSION_AUDIO = exports.NO_CAMERA_AVAILABLE = exports.NO_AUDIO_DEVICE_AVAILABLE = exports.NOT_WATCHING_SCREEN = exports.MESSAGE = exports.FULLSCREEN_ERROR_MESSAGE = exports.DENY_FULLSCREEN = exports.CAMERA_UNAVAILABLE_INSECURE_CONN = exports.BROWSER_BLOCKED_PERMISSION_RESOLVED_RECHECK = exports.BROWSER_BLOCKED_PERMISSION_NEXT_STEP = exports.BROWSER_BLOCKED_PERMISSION_DIRECTION = exports.BROWSER_BLOCKED_PERMISSION_DIALOG = exports.BROWSER_BLOCKED_PERMISSION = exports.ALLOW_SCREENSHARE = exports.ALLOW_FULLSCREEN = void 0;
|
|
7
7
|
const WATCHING_SCREEN = "You are watching the screen";
|
|
8
8
|
exports.WATCHING_SCREEN = WATCHING_SCREEN;
|
|
9
9
|
const NOT_WATCHING_SCREEN = "You are not watching the screen";
|
|
@@ -20,6 +20,8 @@ const DENY_FULLSCREEN = "Deny";
|
|
|
20
20
|
exports.DENY_FULLSCREEN = DENY_FULLSCREEN;
|
|
21
21
|
const ALLOW_FULLSCREEN = "Switch to Fullscreen";
|
|
22
22
|
exports.ALLOW_FULLSCREEN = ALLOW_FULLSCREEN;
|
|
23
|
+
const ALLOW_SCREENSHARE = "Share Screen";
|
|
24
|
+
exports.ALLOW_SCREENSHARE = ALLOW_SCREENSHARE;
|
|
23
25
|
const NO_CAMERA_AVAILABLE = "No Camera available for use.";
|
|
24
26
|
exports.NO_CAMERA_AVAILABLE = NO_CAMERA_AVAILABLE;
|
|
25
27
|
const NO_AUDIO_DEVICE_AVAILABLE = "No audio device available for use";
|
|
@@ -53,4 +55,6 @@ exports.PERMISSION_AUDIO_VIDEO = PERMISSION_AUDIO_VIDEO;
|
|
|
53
55
|
const PERMISSION_VIDEO = "Your browser or system settings have disallowed Camera permissions. Please permit this website to access the camera. Refresh after you've given the permission to access the screen";
|
|
54
56
|
exports.PERMISSION_VIDEO = PERMISSION_VIDEO;
|
|
55
57
|
const PERMISSION_AUDIO = "Your browser or system settings have disallowed Microphone permissions. Please permit this website to access the microphone. Refresh after you've given the permission to access the screen";
|
|
56
|
-
exports.PERMISSION_AUDIO = PERMISSION_AUDIO;
|
|
58
|
+
exports.PERMISSION_AUDIO = PERMISSION_AUDIO;
|
|
59
|
+
const PERMISSION_SCREENSHARE = "Please share your entire screen";
|
|
60
|
+
exports.PERMISSION_SCREENSHARE = PERMISSION_SCREENSHARE;
|
|
@@ -42,18 +42,12 @@ const getIsWatching = async (network, video) => {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
const deviceHasGPU = (0, _utils.isGPUAvailable)();
|
|
46
|
-
|
|
47
45
|
function useWebcamData(webcamReference, canvasReference) {
|
|
48
46
|
const [userCount, setUserCount] = (0, _react.useState)(_defaults.initialValues.userCount);
|
|
49
47
|
const [isWatching, setIsWatching] = (0, _react.useState)(_defaults.initialValues.isWatching);
|
|
50
48
|
const [lookedAwayCount, setLookedAwayCount] = (0, _react.useState)(_defaults.initialValues.lookedAwayCount);
|
|
51
|
-
const [isWebcamDataReliable, setIsWebcamDataReliable] = (0, _react.useState)(_defaults.initialValues.isWebcamDataReliable);
|
|
52
|
-
(0, _react.useEffect)(() => {
|
|
53
|
-
setIsWebcamDataReliable(deviceHasGPU);
|
|
54
|
-
}, []);
|
|
55
49
|
(0, _react.useEffect)(() => {
|
|
56
|
-
if (
|
|
50
|
+
if ((0, _utils.isGPUAvailable)()) {
|
|
57
51
|
const loadBodyPixModel = async () => {
|
|
58
52
|
try {
|
|
59
53
|
const network = await bodyPix.load();
|
|
@@ -95,5 +89,5 @@ function useWebcamData(webcamReference, canvasReference) {
|
|
|
95
89
|
setLookedAwayCount(lookedAwayCount => lookedAwayCount + 1);
|
|
96
90
|
}
|
|
97
91
|
}, [isWatching]);
|
|
98
|
-
return [userCount, lookedAwayCount
|
|
92
|
+
return [userCount, lookedAwayCount];
|
|
99
93
|
}
|
package/dist/index.js
CHANGED
|
@@ -9,13 +9,5 @@ Object.defineProperty(exports, "ProctorApp", {
|
|
|
9
9
|
return _components.ProctorApp;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
-
Object.defineProperty(exports, "getStatistics", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function get() {
|
|
15
|
-
return _utils.getStatistics;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
var _components = require("./components");
|
|
20
12
|
|
|
21
|
-
var
|
|
13
|
+
var _components = require("./components");
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.getDataOnBreach = void 0;
|
|
7
7
|
|
|
8
8
|
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
9
|
|
|
@@ -11,7 +11,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
11
11
|
|
|
12
12
|
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
13
|
|
|
14
|
-
const
|
|
14
|
+
const getDataOnBreach = (statistics, currentData) => {
|
|
15
15
|
const {
|
|
16
16
|
userCount,
|
|
17
17
|
tabSwitchCount,
|
|
@@ -23,59 +23,54 @@ const sendDataOnBreach = (statistics, currentData, proctoringIdentifier, sendDat
|
|
|
23
23
|
const data = statistics.current;
|
|
24
24
|
|
|
25
25
|
if (data.IS_WEBCAM_DATA_RELIABLE !== isWebcamDataReliable) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
breach: "IS_WEBCAM_DATA_RELIABLE",
|
|
26
|
+
return {
|
|
27
|
+
breachedParam: "IS_WEBCAM_DATA_RELIABLE",
|
|
29
28
|
timestamp,
|
|
30
29
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
31
30
|
IS_WEBCAM_DATA_RELIABLE: isWebcamDataReliable
|
|
32
31
|
})
|
|
33
|
-
}
|
|
32
|
+
};
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
if (data.USER_COUNT_MAX < userCount) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
breach: "USER_COUNT_MAX",
|
|
36
|
+
return {
|
|
37
|
+
breachedParam: "USER_COUNT_MAX",
|
|
40
38
|
timestamp,
|
|
41
39
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
42
40
|
USER_COUNT_MAX: userCount
|
|
43
41
|
})
|
|
44
|
-
}
|
|
42
|
+
};
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
if (data.TAB_SWITCH_COUNT !== tabSwitchCount) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
breach: "TAB_SWITCH_COUNT",
|
|
46
|
+
return {
|
|
47
|
+
breachedParam: "TAB_SWITCH_COUNT",
|
|
51
48
|
timestamp,
|
|
52
49
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
53
50
|
TAB_SWITCH_COUNT: tabSwitchCount
|
|
54
51
|
})
|
|
55
|
-
}
|
|
52
|
+
};
|
|
56
53
|
}
|
|
57
54
|
|
|
58
55
|
if (data.FULLSCREEN_EXIT_COUNT !== fullScreenExitCount) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
breach: "FULLSCREEN_EXIT_COUNT",
|
|
56
|
+
return {
|
|
57
|
+
breachedParam: "FULLSCREEN_EXIT_COUNT",
|
|
62
58
|
timestamp,
|
|
63
59
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
64
60
|
FULLSCREEN_EXIT_COUNT: fullScreenExitCount
|
|
65
61
|
})
|
|
66
|
-
}
|
|
62
|
+
};
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
if (data.LOOKED_AWAY_COUNT !== lookedAwayCount) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
breach: "LOOKED_AWAY_COUNT",
|
|
66
|
+
return {
|
|
67
|
+
breachedParam: "LOOKED_AWAY_COUNT",
|
|
73
68
|
timestamp,
|
|
74
69
|
data: _objectSpread(_objectSpread({}, data), {}, {
|
|
75
70
|
LOOKED_AWAY_COUNT: lookedAwayCount
|
|
76
71
|
})
|
|
77
|
-
}
|
|
72
|
+
};
|
|
78
73
|
}
|
|
79
74
|
};
|
|
80
75
|
|
|
81
|
-
exports.
|
|
76
|
+
exports.getDataOnBreach = getDataOnBreach;
|
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,15 +3,42 @@
|
|
|
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.setupScreensharePermission = exports.isWebcamVideoValid = exports.getVideoPermissionQuery = exports.getVideoPermission = exports.getGlancePercentage = exports.getAudioVideoPermission = exports.getAudioPermissionQuery = exports.getAudioPermission = exports.captureWebcamSnapshot = exports.captureScreenshot = void 0;
|
|
7
|
+
|
|
8
|
+
require("core-js/modules/es.regexp.exec.js");
|
|
9
|
+
|
|
10
|
+
require("core-js/modules/es.string.split.js");
|
|
11
|
+
|
|
12
|
+
require("core-js/modules/es.array-buffer.slice.js");
|
|
13
|
+
|
|
14
|
+
require("core-js/modules/es.typed-array.uint8-array.js");
|
|
15
|
+
|
|
16
|
+
require("core-js/modules/es.typed-array.set.js");
|
|
17
|
+
|
|
18
|
+
require("core-js/modules/es.typed-array.sort.js");
|
|
19
|
+
|
|
20
|
+
require("core-js/modules/es.typed-array.to-locale-string.js");
|
|
21
|
+
|
|
22
|
+
require("core-js/modules/es.promise.js");
|
|
7
23
|
|
|
8
24
|
var _ = require(".");
|
|
9
25
|
|
|
26
|
+
var _html2canvas = _interopRequireDefault(require("html2canvas"));
|
|
27
|
+
|
|
28
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
29
|
+
|
|
10
30
|
const isWebcamVideoValid = webcamReference => webcamReference !== null && webcamReference !== undefined && typeof webcamReference.current !== "undefined" && webcamReference.current !== null && webcamReference.current.video.readyState === 4;
|
|
11
31
|
|
|
12
32
|
exports.isWebcamVideoValid = isWebcamVideoValid;
|
|
13
33
|
|
|
14
|
-
const updateStatistics = (statistics,
|
|
34
|
+
const updateStatistics = (statistics, currentStats) => {
|
|
35
|
+
const {
|
|
36
|
+
tabSwitchCount,
|
|
37
|
+
fullScreenExitCount,
|
|
38
|
+
lookedAwayCount,
|
|
39
|
+
userCount,
|
|
40
|
+
isWebcamDataReliable
|
|
41
|
+
} = currentStats;
|
|
15
42
|
statistics.current.TAB_SWITCH_COUNT = tabSwitchCount;
|
|
16
43
|
statistics.current.FULLSCREEN_EXIT_COUNT = fullScreenExitCount;
|
|
17
44
|
statistics.current.LOOKED_AWAY_COUNT = lookedAwayCount;
|
|
@@ -103,6 +130,34 @@ const updateVideoPermissions = setVideoPermission => {
|
|
|
103
130
|
|
|
104
131
|
exports.updateVideoPermissions = updateVideoPermissions;
|
|
105
132
|
|
|
133
|
+
const setupScreensharePermission = (setScreensharePermission, screenshareReference) => navigator.mediaDevices.getDisplayMedia({
|
|
134
|
+
video: true
|
|
135
|
+
}).then(stream => {
|
|
136
|
+
const track = stream.getTracks()[0];
|
|
137
|
+
|
|
138
|
+
if (track.getSettings().displaySurface === "monitor") {
|
|
139
|
+
screenshareReference.current.srcObject = stream;
|
|
140
|
+
|
|
141
|
+
screenshareReference.current.onloadedmetadata = e => {
|
|
142
|
+
screenshareReference.current.play();
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
track.onended = e => {
|
|
146
|
+
setScreensharePermission(false);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
setScreensharePermission(true);
|
|
150
|
+
} else {
|
|
151
|
+
screenshareReference.current = null;
|
|
152
|
+
setScreensharePermission(false);
|
|
153
|
+
}
|
|
154
|
+
}).catch(e => {
|
|
155
|
+
screenshareReference.current = null;
|
|
156
|
+
setScreensharePermission(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
exports.setupScreensharePermission = setupScreensharePermission;
|
|
160
|
+
|
|
106
161
|
const getVideoPermissionQuery = () => navigator.permissions.query({
|
|
107
162
|
name: "camera"
|
|
108
163
|
});
|
|
@@ -113,4 +168,39 @@ const getAudioPermissionQuery = () => navigator.permissions.query({
|
|
|
113
168
|
name: "microphone"
|
|
114
169
|
});
|
|
115
170
|
|
|
116
|
-
exports.getAudioPermissionQuery = getAudioPermissionQuery;
|
|
171
|
+
exports.getAudioPermissionQuery = getAudioPermissionQuery;
|
|
172
|
+
|
|
173
|
+
const b64DataURItoBlob = dataURI => {
|
|
174
|
+
const byteString = window.atob(dataURI.split(",")[1]);
|
|
175
|
+
const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
|
|
176
|
+
const u8arr = new Uint8Array(byteString.length);
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < byteString.length; i += 1) {
|
|
179
|
+
u8arr[i] = byteString.charCodeAt(i);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return new Blob([u8arr], {
|
|
183
|
+
type: mimeString
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const captureWebcamSnapshot = webcamReference => {
|
|
188
|
+
try {
|
|
189
|
+
const b64Snapshot = webcamReference.current.getScreenshot();
|
|
190
|
+
return b64DataURItoBlob(b64Snapshot);
|
|
191
|
+
} catch (e) {// pass
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
exports.captureWebcamSnapshot = captureWebcamSnapshot;
|
|
196
|
+
|
|
197
|
+
const captureScreenshot = async () => {
|
|
198
|
+
try {
|
|
199
|
+
const canvas = await (0, _html2canvas.default)(document.querySelector("#ss-ref"));
|
|
200
|
+
const b64Snapshot = canvas.toDataURL("image/jpeg");
|
|
201
|
+
return b64DataURItoBlob(b64Snapshot);
|
|
202
|
+
} catch (e) {// pass
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
exports.captureScreenshot = captureScreenshot;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newtonschool/react_proctoring_library",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Used to proctor online tests",
|
|
5
5
|
"author": "ayushkagrawal,shreyachandra",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@tensorflow/tfjs": "^3.9.0",
|
|
18
18
|
"bootstrap": "^5.1.3",
|
|
19
19
|
"core-js": "^3.22.7",
|
|
20
|
+
"html2canvas": "^1.4.1",
|
|
20
21
|
"react-bootstrap": "^2.0.4",
|
|
21
22
|
"react-webcam": "^6.0.0"
|
|
22
23
|
},
|