[mirotalk] - #195 improve host protection, add auth user & new URL params
This commit is contained in:
+11
-2
@@ -5,9 +5,18 @@ HTTPS=false # true or false
|
||||
# Domain
|
||||
|
||||
HOST=localhost
|
||||
|
||||
# Host protection
|
||||
# HOST_PROTECTED: When set to true, it requires a valid username and password from the HOST_USERS list to initialize or join a room.
|
||||
# HOST_USER_AUTH: When set to true, it also requires a valid username and password, but these need to be provided in the URL parameters.
|
||||
# HOST_USERS: This is the list of valid host users along with their credentials.
|
||||
|
||||
HOST_PROTECTED=false # true or false
|
||||
HOST_USERNAME=username
|
||||
HOST_PASSWORD=password
|
||||
|
||||
HOST_USER_AUTH=false # true or false
|
||||
|
||||
HOST_USERS='[{"username": "username", "password": "password"},{"username": "username2", "password": "password2"}]'
|
||||
|
||||
|
||||
# Signaling Server listen port
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
- Unlimited conference rooms with no time limitations.
|
||||
- Translated into 133 languages.
|
||||
- Host protection to prevent unauthorized access.
|
||||
- User auth to prevent unauthorized access.
|
||||
- Room password protection.
|
||||
- Compatible with desktop and mobile devices.
|
||||
- Optimized mobile room URL sharing.
|
||||
@@ -91,26 +92,74 @@
|
||||
<br/>
|
||||
|
||||
- You can `directly join a room` by using links like:
|
||||
- https://p2p.mirotalk.com/join?room=test&name=mirotalk&audio=0&video=0&screen=0¬ify=0
|
||||
- https://mirotalk.up.railway.app/join?room=test&name=mirotalk&audio=0&video=0&screen=0¬ify=0
|
||||
- https://p2p.mirotalk.com/join?room=test&name=mirotalk&audio=0&video=0&screen=0&hide=0¬ify=0
|
||||
- https://mirotalk.up.railway.app/join?room=test&name=mirotalk&audio=0&video=0&screen=0&hide=0¬ify=0
|
||||
|
||||
| Params | Type | Description |
|
||||
| ------ | ------- | --------------- |
|
||||
| room | string | Room Id |
|
||||
| name | string | User name |
|
||||
| audio | boolean | Audio stream |
|
||||
| video | boolean | Video stream |
|
||||
| screen | boolean | Screen stream |
|
||||
| notify | boolean | Welcome message |
|
||||
| Params | Type | Description |
|
||||
| -------- | ------- | --------------- |
|
||||
| room | string | Room Id |
|
||||
| name | string | User name |
|
||||
| audio | boolean | Audio stream |
|
||||
| video | boolean | Video stream |
|
||||
| screen | boolean | Screen stream |
|
||||
| hide | boolean | Hide myself |
|
||||
| notify | boolean | Welcome message |
|
||||
| username | string | auth username |
|
||||
| password | string | auth password |
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> When [host protection is enabled](https://github.com/miroslavpejic85/mirotalk/commit/285c92605585bf204996dc0bade9b3e7c62d75df#commitcomment-103108955) the host needs to provide a valid username and password as specified in the `.env`.
|
||||
>
|
||||
> After host authentication, participants can join the room using any of the following URL formats:
|
||||
>
|
||||
> - https://p2p.mirotalk.com/join/test (URL path)
|
||||
> - https://p2p.mirotalk.com/join/?room=test&name=mirotalk&audio=0&video=0&screen=0¬ify=0 (URL with query parameters for direct join)
|
||||
> The `username` and `password` parameters are required when either `HOST_PROTECTED` or `HOST_USER_AUTH` is set to `true` in the `.env` file. The valid list of users is defined in the `HOST_USERS` configuration.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Host Protection Configuration</summary>
|
||||
|
||||
<br/>
|
||||
|
||||
When [host protection](https://github.com/miroslavpejic85/mirotalk/commit/285c92605585bf204996dc0bade9b3e7c62d75df#commitcomment-103108955) or host user auth is enabled, the host/users must provide a valid username and password as specified in the `.env` file.
|
||||
|
||||
### `HOST_PROTECTED`
|
||||
|
||||
- **Description:** Requires the host to provide a valid username and password during room initialization.
|
||||
- **Values:** `true` if protection is enabled, `false` if not (default false).
|
||||
|
||||
### `HOST_USER_AUTH`
|
||||
|
||||
- **Description:** Determines whether host authentication is required.
|
||||
- **Values:** `true` if user authentication is required, `false` if not (default false).
|
||||
|
||||
### `HOST_USERS`
|
||||
|
||||
- **Description:** List of valid host users with their credentials.
|
||||
- **Format:** JSON array with user objects: `{"username": "username", "password": "password"}`
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
HOST_USERS='[{"username": "username", "password": "password"},{"username": "username2", "password": "password2"}]'
|
||||
```
|
||||
|
||||
### Room Initialization
|
||||
|
||||
To bypass the login page, join the room with URL parameters:
|
||||
|
||||
- [https://p2p.mirotalk.com/join/?room=test&username=username&password=password](https://p2p.mirotalk.com/join/?room=test&username=username&password=password)
|
||||
|
||||
### Participant Room Entry
|
||||
|
||||
If `HOST_PROTECTED` is enabled, participants can join using:
|
||||
|
||||
- [https://p2p.mirotalk.com/join/test](https://p2p.mirotalk.com/join/test) (URL path)
|
||||
- [https://p2p.mirotalk.com/join/?room=test&name=mirotalk&audio=0&video=0&screen=0&hide=0¬ify=0](https://p2p.mirotalk.com/join/?room=test&name=mirotalk&audio=0&video=0&screen=0&hide=0¬ify=0) (URL with query parameters)
|
||||
|
||||
If `HOST_USER_AUTH` is enabled, participants can join with mandatory credentials:
|
||||
|
||||
- [https://p2p.mirotalk.com/join/?room=test&username=username&password=password](https://p2p.mirotalk.com/join/?room=test&username=username&password=password) (URL path)
|
||||
- [https://p2p.mirotalk.com/join/?room=test&name=mirotalk&audio=0&video=0&screen=0&hide=0¬ify=0&username=username&password=password](https://p2p.mirotalk.com/join/?room=test&name=mirotalk&audio=0&video=0&screen=0&hide=0¬ify=0&username=username&password=password) (URL with query parameters)
|
||||
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
+93
-38
@@ -38,7 +38,7 @@ dependencies: {
|
||||
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.2.3
|
||||
* @version 1.2.4
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -90,10 +90,13 @@ io = new Server({
|
||||
|
||||
// Host protection (disabled by default)
|
||||
const hostProtected = getEnvBoolean(process.env.HOST_PROTECTED);
|
||||
const userAuth = getEnvBoolean(process.env.HOST_USER_AUTH);
|
||||
const hostUsersString = process.env.HOST_USERS || '[{"username": "MiroTalk", "password": "P2P"}]';
|
||||
const hostUsers = JSON.parse(hostUsersString);
|
||||
const hostCfg = {
|
||||
protected: hostProtected,
|
||||
username: process.env.HOST_USERNAME,
|
||||
password: process.env.HOST_PASSWORD,
|
||||
user_auth: userAuth,
|
||||
users: hostUsers,
|
||||
authenticated: !hostProtected,
|
||||
};
|
||||
|
||||
@@ -311,19 +314,36 @@ app.get(['/test'], (req, res) => {
|
||||
|
||||
// no room name specified to join
|
||||
app.get('/join/', (req, res) => {
|
||||
if (hostCfg.authenticated && Object.keys(req.query).length > 0) {
|
||||
if (Object.keys(req.query).length > 0) {
|
||||
log.debug('Request Query', req.query);
|
||||
/*
|
||||
http://localhost:3000/join?room=test&name=mirotalk&audio=1&video=1&screen=1¬ify=1
|
||||
https://p2p.mirotalk.com/join?room=test&name=mirotalk&audio=1&video=1&screen=1¬ify=1
|
||||
https://mirotalk.up.railway.app/join?room=test&name=mirotalk&audio=1&video=1&screen=1¬ify=1
|
||||
http://localhost:3000/join?room=test&name=mirotalk&audio=1&video=1&screen=0¬ify=0&hide=1&username=username&password=password
|
||||
https://p2p.mirotalk.com/join?room=test&name=mirotalk&audio=1&video=1&screen=0¬ify=0&hide=0
|
||||
https://mirotalk.up.railway.app/join?room=test&name=mirotalk&audio=1&video=1&screen=0¬ify=0&hide=0
|
||||
*/
|
||||
const { room, name, audio, video, screen, notify } = checkXSS(req.query);
|
||||
// all the params are mandatory for the direct room join
|
||||
// if (room && name && audio && video && screen && notify) {
|
||||
if (room) {
|
||||
const { room, name, audio, video, screen, notify, hide, username, password } = checkXSS(req.query);
|
||||
|
||||
// check if valid peer
|
||||
const isPeerValid = isAuthPeer(username, password);
|
||||
|
||||
// Peer valid going to auth as host
|
||||
if (hostCfg.protected && isPeerValid && !hostCfg.authenticated) {
|
||||
const ip = getIP(req);
|
||||
hostCfg.authenticated = true;
|
||||
authHost = new Host(ip, true);
|
||||
log.debug('Direct Join user auth as host done', {
|
||||
ip: ip,
|
||||
username: username,
|
||||
password: password,
|
||||
});
|
||||
}
|
||||
|
||||
// Check if peer authenticated or valid
|
||||
if (room && (hostCfg.authenticated || isPeerValid)) {
|
||||
// only room mandatory
|
||||
return res.sendFile(views.client);
|
||||
} else {
|
||||
return res.sendFile(views.login);
|
||||
}
|
||||
}
|
||||
if (hostCfg.protected) {
|
||||
@@ -350,7 +370,12 @@ app.get('/join/*', function (req, res) {
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
// logged
|
||||
// Login
|
||||
app.get(['/login'], (req, res) => {
|
||||
res.sendFile(views.login);
|
||||
});
|
||||
|
||||
// Logged
|
||||
app.get(['/logged'], (req, res) => {
|
||||
const ip = getIP(req);
|
||||
if (allowedIP(ip)) {
|
||||
@@ -365,22 +390,29 @@ app.get(['/logged'], (req, res) => {
|
||||
|
||||
// handle login on host protected
|
||||
app.post(['/login'], (req, res) => {
|
||||
if (hostCfg.protected) {
|
||||
//
|
||||
const ip = getIP(req);
|
||||
log.debug(`Request login to host from: ${ip}`, req.body);
|
||||
|
||||
const { username, password } = checkXSS(req.body);
|
||||
|
||||
const isPeerValid = isAuthPeer(username, password);
|
||||
|
||||
// Peer valid going to auth as host
|
||||
if (hostCfg.protected && isPeerValid && !hostCfg.authenticated) {
|
||||
const ip = getIP(req);
|
||||
log.debug(`Request login to host from: ${ip}`, req.body);
|
||||
const { username, password } = checkXSS(req.body);
|
||||
if (username == hostCfg.username && password == hostCfg.password) {
|
||||
hostCfg.authenticated = true;
|
||||
authHost = new Host(ip, true);
|
||||
log.debug('LOGIN OK', { ip: ip, authorized: authHost.isAuthorized(ip) });
|
||||
res.status(200).json({ message: 'authorized' });
|
||||
} else {
|
||||
log.debug('LOGIN KO', { ip: ip, authorized: false });
|
||||
hostCfg.authenticated = false;
|
||||
res.status(401).json({ message: 'unauthorized' });
|
||||
}
|
||||
hostCfg.authenticated = true;
|
||||
authHost = new Host(ip, true);
|
||||
log.debug('HOST LOGIN OK', { ip: ip, authorized: authHost.isAuthorized(ip) });
|
||||
return res.status(200).json({ message: 'authorized' });
|
||||
}
|
||||
|
||||
// Peer auth valid
|
||||
if (isPeerValid) {
|
||||
log.debug('PEER LOGIN OK', { ip: ip, authorized: true });
|
||||
return res.status(200).json({ message: 'authorized' });
|
||||
} else {
|
||||
res.redirect('/');
|
||||
return res.status(401).json({ message: 'unauthorized' });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -482,10 +514,8 @@ async function ngrokStart() {
|
||||
const tunnelHttps = pu0.startsWith('https') ? pu0 : pu1;
|
||||
// server settings
|
||||
log.debug('settings', {
|
||||
host_protected: hostCfg.protected,
|
||||
host_username: hostCfg.username,
|
||||
host_password: hostCfg.password,
|
||||
iceServers: iceServers,
|
||||
host: hostCfg,
|
||||
ngrok: {
|
||||
ngrok_enabled: ngrokEnabled,
|
||||
ngrok_token: ngrokAuthToken,
|
||||
@@ -537,10 +567,8 @@ server.listen(port, null, () => {
|
||||
} else {
|
||||
// server settings
|
||||
log.debug('settings', {
|
||||
host_protected: hostCfg.protected,
|
||||
host_username: hostCfg.username,
|
||||
host_password: hostCfg.password,
|
||||
iceServers: iceServers,
|
||||
host: hostCfg,
|
||||
server: host,
|
||||
test_ice_servers: testStunTurn,
|
||||
api_docs: api_docs,
|
||||
@@ -691,6 +719,8 @@ io.sockets.on('connect', async (socket) => {
|
||||
channel_password,
|
||||
peer_uuid,
|
||||
peer_name,
|
||||
peer_username,
|
||||
peer_password,
|
||||
peer_video,
|
||||
peer_audio,
|
||||
peer_video_status,
|
||||
@@ -713,6 +743,23 @@ io.sockets.on('connect', async (socket) => {
|
||||
// no presenter aka host in presenters init
|
||||
if (!(channel in presenters)) presenters[channel] = {};
|
||||
|
||||
// User Auth required, we check if peer valid
|
||||
if (hostCfg.user_auth) {
|
||||
const isPeerValid = isAuthPeer(peer_username, peer_password);
|
||||
|
||||
log.debug('[' + socket.id + '] JOIN ROOM - HOST PROTECTED - USER AUTH check peer', {
|
||||
ip: peer_ip,
|
||||
peer_username: peer_username,
|
||||
peer_password: peer_password,
|
||||
peer_valid: isPeerValid,
|
||||
});
|
||||
|
||||
if (!isPeerValid) {
|
||||
// redirect peer to login page
|
||||
return socket.emit('unauthorized');
|
||||
}
|
||||
}
|
||||
|
||||
// room locked by the participants can't join
|
||||
if (peers[channel]['lock'] === true && peers[channel]['password'] != channel_password) {
|
||||
log.debug('[' + socket.id + '] [Warning] Room Is Locked', channel);
|
||||
@@ -759,6 +806,8 @@ io.sockets.on('connect', async (socket) => {
|
||||
// Send some server info to joined peer
|
||||
await sendToPeer(socket.id, sockets, 'serverInfo', {
|
||||
peers_count: peerCounts,
|
||||
host_protected: hostCfg.protected,
|
||||
user_auth: hostCfg.user_auth,
|
||||
is_presenter: isPresenter,
|
||||
survey: {
|
||||
active: surveyEnabled,
|
||||
@@ -1279,15 +1328,21 @@ async function isPeerPresenter(room_id, peer_id, peer_name, peer_uuid) {
|
||||
log.error('isPeerPresenter', err);
|
||||
return false;
|
||||
}
|
||||
log.debug('[' + peer_id + '] isPeerPresenter', {
|
||||
peer_name: peer_name,
|
||||
peer_uuid: peer_uuid,
|
||||
isPresenter: isPresenter,
|
||||
presenter: presenters[room_id],
|
||||
});
|
||||
log.debug('[' + peer_id + '] isPeerPresenter', presenters[room_id]);
|
||||
|
||||
return isPresenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if peer is present in the host users
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @returns Boolean true/false
|
||||
*/
|
||||
function isAuthPeer(username, password) {
|
||||
return hostCfg.users && hostCfg.users.some((user) => user.username === username && user.password === password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ip
|
||||
* @param {object} req
|
||||
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalk",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.4",
|
||||
"description": "A free WebRTC browser-based video call",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
@@ -34,9 +34,9 @@
|
||||
"license": "AGPL-3.0",
|
||||
"homepage": "https://github.com/miroslavpejic85/mirotalk",
|
||||
"dependencies": {
|
||||
"@sentry/integrations": "^7.80.0",
|
||||
"@sentry/node": "^7.80.0",
|
||||
"axios": "^1.6.1",
|
||||
"@sentry/integrations": "^7.81.1",
|
||||
"@sentry/node": "^7.81.1",
|
||||
"axios": "^1.6.2",
|
||||
"body-parser": "^1.20.2",
|
||||
"colors": "^1.4.0",
|
||||
"compression": "^1.7.4",
|
||||
@@ -45,7 +45,7 @@
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"ngrok": "^4.3.3",
|
||||
"openai": "^4.17.4",
|
||||
"openai": "^4.19.1",
|
||||
"qs": "^6.11.2",
|
||||
"socket.io": "^4.7.2",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
@@ -56,6 +56,6 @@
|
||||
"devDependencies": {
|
||||
"node-fetch": "^3.3.2",
|
||||
"nodemon": "^3.0.1",
|
||||
"prettier": "3.0.3"
|
||||
"prettier": "3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
+104
-13
@@ -15,7 +15,7 @@
|
||||
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.2.3
|
||||
* @version 1.2.4
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -501,6 +501,8 @@ let isDocumentOnFullScreen = false;
|
||||
let myPeerId; // This socket.id
|
||||
let myPeerUUID = getUUID(); // Unique peer id
|
||||
let myPeerName = getPeerName();
|
||||
let myUsername = window.sessionStorage.peer_username ? window.sessionStorage.peer_username : getPeerUsername(); // default false if not passed by query params
|
||||
let myPassword = window.sessionStorage.peer_password ? window.sessionStorage.peer_password : getPeerPassword(); // default false if not passed by query params
|
||||
let isPresenter = false; // True Who init the room (aka first peer joined)
|
||||
let myHandStatus = false;
|
||||
let myVideoStatus = false;
|
||||
@@ -561,7 +563,7 @@ let isVideoFullScreenSupported = true;
|
||||
let isVideoOnFullScreen = false;
|
||||
let isScreenSharingSupported = false;
|
||||
let isScreenStreaming = false;
|
||||
let isHideMeActive = false; // Hide myself from the meeting view
|
||||
let isHideMeActive = getHideMeActive();
|
||||
let remoteMediaControls = false; // enable - disable peers video player controls (default false)
|
||||
let camera = 'user'; // user = front-facing camera on a smartphone. | environment = the back camera on a smartphone.
|
||||
|
||||
@@ -631,6 +633,10 @@ let receiveInProgress = false;
|
||||
*/
|
||||
const chunkSize = 1024; // 1024 * 16; // 16kb/s
|
||||
|
||||
// server
|
||||
let isHostProtected = false; // Username and Password required to initialize room
|
||||
let isPeerAuthEnabled = false; // Username and Password required in the URL params to join room
|
||||
|
||||
// survey
|
||||
let surveyActive = true; // when leaving the room give a feedback, if false will be redirected to newcall page
|
||||
let surveyURL = 'https://www.questionpro.com/t/AUs7VZq00L';
|
||||
@@ -896,6 +902,36 @@ function getNotify() {
|
||||
return notify;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Peer username
|
||||
* @returns {mixed} boolean false or username string
|
||||
*/
|
||||
function getPeerUsername() {
|
||||
let qs = new URLSearchParams(window.location.search);
|
||||
let username = filterXSS(qs.get('username'));
|
||||
let queryUsername = false;
|
||||
if (username) {
|
||||
queryUsername = username;
|
||||
}
|
||||
console.log('Direct join', { username: queryUsername });
|
||||
return queryUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Peer password
|
||||
* @returns {mixed} boolean false or password string
|
||||
*/
|
||||
function getPeerPassword() {
|
||||
let qs = new URLSearchParams(window.location.search);
|
||||
let password = filterXSS(qs.get('password'));
|
||||
let queryPassword = false;
|
||||
if (password) {
|
||||
queryPassword = password;
|
||||
}
|
||||
console.log('Direct join', { password: queryPassword });
|
||||
return queryPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if peer name is set
|
||||
* @returns {string} Peer Name
|
||||
@@ -928,6 +964,22 @@ function getScreenEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide myself from the meeting view
|
||||
* @returns {boolean} true/false
|
||||
*/
|
||||
function getHideMeActive() {
|
||||
let qs = new URLSearchParams(window.location.search);
|
||||
let hide = filterXSS(qs.get('hide'));
|
||||
let queryHideMe = false;
|
||||
if (hide) {
|
||||
hide = hide.toLowerCase();
|
||||
queryHideMe = hide === '1' || hide === 'true';
|
||||
}
|
||||
console.log('Direct join', { hide: queryHideMe });
|
||||
return queryHideMe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is peer connections
|
||||
* @returns {boolean} true/false
|
||||
@@ -991,6 +1043,7 @@ function initClientPeer() {
|
||||
|
||||
// on receiving data from signaling server...
|
||||
signalingSocket.on('connect', handleConnect);
|
||||
signalingSocket.on('unauthorized', handleUnauthorized);
|
||||
signalingSocket.on('roomIsLocked', handleUnlockTheRoom);
|
||||
signalingSocket.on('roomAction', handleRoomAction);
|
||||
signalingSocket.on('addPeer', handleAddPeer);
|
||||
@@ -1071,7 +1124,10 @@ async function handleConnect() {
|
||||
function handleServerInfo(config) {
|
||||
console.log('13. Server info', config);
|
||||
|
||||
const { peers_count, is_presenter, survey, redirect } = config;
|
||||
const { peers_count, host_protected, user_auth, is_presenter, survey, redirect } = config;
|
||||
|
||||
isHostProtected = host_protected;
|
||||
isPeerAuthEnabled = user_auth;
|
||||
|
||||
// Get survey settings from server
|
||||
surveyActive = survey.active;
|
||||
@@ -1100,6 +1156,27 @@ function handleServerInfo(config) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HOST_USER_AUTH enabled and peer not match valid username and password
|
||||
*/
|
||||
function handleUnauthorized() {
|
||||
playSound('alert');
|
||||
Swal.fire({
|
||||
allowOutsideClick: false,
|
||||
allowEscapeKey: false,
|
||||
background: swBg,
|
||||
imageUrl: images.forbidden,
|
||||
title: 'Oops, Unauthorized',
|
||||
text: 'The host has user authentication enabled',
|
||||
confirmButtonText: `Login`,
|
||||
showClass: { popup: 'animate__animated animate__fadeInDown' },
|
||||
hideClass: { popup: 'animate__animated animate__fadeOutUp' },
|
||||
}).then(() => {
|
||||
// Login required to join room
|
||||
openURL(`/login/?room=${roomId}`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Room is busy, disconnect me and alert the user that
|
||||
* will be redirected to home page
|
||||
@@ -1554,12 +1631,12 @@ function checkPeerAudioVideo() {
|
||||
* Room and Peer name are ok Join Channel
|
||||
*/
|
||||
async function whoAreYouJoin() {
|
||||
elemDisplay(myVideoWrap, true);
|
||||
myVideoParagraph.innerText = myPeerName + ' (me)';
|
||||
setPeerAvatarImgName('myVideoAvatarImage', myPeerName);
|
||||
setPeerAvatarImgName('myProfileAvatar', myPeerName);
|
||||
setPeerChatAvatarImgName('right', myPeerName);
|
||||
joinToChannel();
|
||||
handleHideMe(isHideMeActive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1574,6 +1651,8 @@ async function joinToChannel() {
|
||||
peer_info: peerInfo,
|
||||
peer_uuid: myPeerUUID,
|
||||
peer_name: myPeerName,
|
||||
peer_username: myUsername,
|
||||
peer_password: myPassword,
|
||||
peer_video: useVideo,
|
||||
peer_audio: useAudio,
|
||||
peer_video_status: myVideoStatus,
|
||||
@@ -2404,10 +2483,11 @@ async function loadLocalMedia(stream, kind) {
|
||||
|
||||
// session time
|
||||
mySessionTime.setAttribute('id', 'mySessionTime');
|
||||
mySessionTime.className = 'notranslate';
|
||||
|
||||
// my peer name
|
||||
myPeerName.setAttribute('id', 'myVideoParagraph');
|
||||
myPeerName.className = 'videoPeerName';
|
||||
myPeerName.className = 'videoPeerName notranslate';
|
||||
|
||||
// my hand status element
|
||||
myHandStatusIcon.setAttribute('id', 'myHandStatusIcon');
|
||||
@@ -2792,7 +2872,7 @@ async function loadRemoteMediaStream(stream, peers, peer_id, kind) {
|
||||
remoteMedia.setAttribute('id', peer_id + '___video');
|
||||
remoteMedia.setAttribute('playsinline', true);
|
||||
remoteMedia.autoplay = true;
|
||||
isMobileDevice ? (remoteMediaControls = false) : (remoteMediaControls = remoteMediaControls);
|
||||
remoteMediaControls = isMobileDevice ? false : remoteMediaControls;
|
||||
remoteMedia.style.objectFit = peer_screen_status ? 'contain' : 'var(--video-object-fit)';
|
||||
remoteMedia.style.name = peer_id + (peer_screen_status ? '_typeScreen' : '_typeCam');
|
||||
remoteMedia.controls = remoteMediaControls;
|
||||
@@ -4965,7 +5045,8 @@ async function shareRoomUrl() {
|
||||
if (navigator.share) {
|
||||
try {
|
||||
// not add title and description to load metadata from url
|
||||
await navigator.share({ url: myRoomUrl });
|
||||
const roomURL = getRoomURL();
|
||||
await navigator.share({ url: roomURL });
|
||||
userLog('toast', 'Room Shared successfully!');
|
||||
} catch (err) {
|
||||
/*
|
||||
@@ -4988,6 +5069,7 @@ async function shareRoomUrl() {
|
||||
*/
|
||||
function shareRoomMeetingURL(checkScreen = false) {
|
||||
playSound('newMessage');
|
||||
const roomURL = getRoomURL();
|
||||
Swal.fire({
|
||||
background: swBg,
|
||||
position: 'center',
|
||||
@@ -4999,7 +5081,7 @@ function shareRoomMeetingURL(checkScreen = false) {
|
||||
<br/>
|
||||
<p style="color:rgb(8, 189, 89);">Join from your mobile device</p>
|
||||
<p style="background:transparent; color:white; font-family: Arial, Helvetica, sans-serif;">No need for apps, simply capture the QR code with your mobile camera Or Invite someone else to join by sending them the following URL</p>
|
||||
<p style="color:rgb(8, 189, 89);">${myRoomUrl}</p>`,
|
||||
<p style="color:rgb(8, 189, 89);">${roomURL}</p>`,
|
||||
showDenyButton: true,
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: 'red',
|
||||
@@ -5039,7 +5121,7 @@ function makeRoomQR() {
|
||||
* Copy Room URL to clipboard
|
||||
*/
|
||||
function copyRoomURL() {
|
||||
const roomURL = window.location.href;
|
||||
const roomURL = getRoomURL();
|
||||
const tmpInput = document.createElement('input');
|
||||
document.body.appendChild(tmpInput);
|
||||
tmpInput.value = roomURL;
|
||||
@@ -5069,11 +5151,12 @@ function shareRoomByEmail() {
|
||||
showClass: { popup: 'animate__animated animate__fadeInDown' },
|
||||
hideClass: { popup: 'animate__animated animate__fadeOutUp' },
|
||||
preConfirm: () => {
|
||||
const roomURL = getRoomURL();
|
||||
const selectedDateTime = document.getElementById('datetimePicker').value;
|
||||
const newLine = '%0D%0A%0D%0A';
|
||||
const email = '';
|
||||
const emailSubject = `Please join our MiroTalk P2P Video Chat Meeting`;
|
||||
const emailBody = `The meeting is scheduled at: ${newLine} DateTime: ${selectedDateTime} ${newLine} Click to join: ${myRoomUrl} ${newLine}`;
|
||||
const emailBody = `The meeting is scheduled at: ${newLine} DateTime: ${selectedDateTime} ${newLine} Click to join: ${roomURL} ${newLine}`;
|
||||
document.location = 'mailto:' + email + '?subject=' + emailSubject + '&body=' + emailBody;
|
||||
},
|
||||
});
|
||||
@@ -5084,6 +5167,16 @@ function shareRoomByEmail() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Room URL
|
||||
* @returns {url} roomURL
|
||||
*/
|
||||
function getRoomURL() {
|
||||
return isHostProtected && isPeerAuthEnabled
|
||||
? window.location.origin + '/join/?room=' + roomId + '&username=' + myUsername + '&password=' + myPassword
|
||||
: myRoomUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Audio ON - OFF
|
||||
* @param {object} e event
|
||||
@@ -7071,9 +7164,7 @@ function handleHideMe(isHideMeActive) {
|
||||
setColor(hideMeBtn, 'black');
|
||||
playSound('on');
|
||||
}
|
||||
if (Object.keys(peerConnections).length === 1) {
|
||||
resizeVideoMedia();
|
||||
}
|
||||
resizeVideoMedia();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,14 +71,14 @@
|
||||
i
|
||||
? (i.classList.add('is-active'), l.classList.add('is-active'))
|
||||
: 'next' === t
|
||||
? (e.firstElementChild.classList.add('is-active'),
|
||||
e.parentNode
|
||||
.getElementsByClassName('carousel-bullets')[0]
|
||||
.firstElementChild.classList.add('is-active'))
|
||||
: (e.lastElementChild.classList.add('is-active'),
|
||||
e.parentNode
|
||||
.getElementsByClassName('carousel-bullets')[0]
|
||||
.lastElementChild.classList.add('is-active'));
|
||||
? (e.firstElementChild.classList.add('is-active'),
|
||||
e.parentNode
|
||||
.getElementsByClassName('carousel-bullets')[0]
|
||||
.firstElementChild.classList.add('is-active'))
|
||||
: (e.lastElementChild.classList.add('is-active'),
|
||||
e.parentNode
|
||||
.getElementsByClassName('carousel-bullets')[0]
|
||||
.lastElementChild.classList.add('is-active'));
|
||||
}
|
||||
|
||||
function i(e, t) {
|
||||
|
||||
@@ -611,7 +611,7 @@ access to use this app.
|
||||
<div id="tabRecording" class="tabcontent">
|
||||
<img id="recImage" src="../images/recording.png" />
|
||||
<div style="display: table-row">
|
||||
<span class="clw" id="recordingTime"></span>
|
||||
<span class="clw notranslate" id="recordingTime"></span>
|
||||
<br />
|
||||
<button id="pauseRecBtn" class="buttons" style="display: none">
|
||||
<i class="far fa-pause-circle"></i>
|
||||
|
||||
@@ -153,6 +153,10 @@
|
||||
.then(function (response) {
|
||||
console.log(response);
|
||||
|
||||
// Store in session
|
||||
window.sessionStorage.peer_username = username;
|
||||
window.sessionStorage.peer_password = password;
|
||||
|
||||
if (room) {
|
||||
return (window.location.href =
|
||||
'/join/' + window.location.search);
|
||||
|
||||
Reference in New Issue
Block a user