init
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
2025-09-02 14:49:16 +08:00
commit 38ba663466
2885 changed files with 391107 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
/**
* The type of (redux) action to update the dropbox access token.
*
* {
* type: UPDATE_DROPBOX_TOKEN,
* token: string
* }
*/
export const UPDATE_DROPBOX_TOKEN = 'UPDATE_DROPBOX_TOKEN';

View File

@@ -0,0 +1,56 @@
import { IStore } from '../app/types';
import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
import { _authorizeDropbox } from './functions';
import logger from './logger';
/**
* Action to authorize the Jitsi Recording app in dropbox.
*
* @returns {Function}
*/
export function authorizeDropbox() {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState();
const { locationURL } = state['features/base/connection'];
const { dropbox = { appKey: '',
redirectURI: undefined } } = state['features/base/config'];
// By default we use the static page on the main domain for redirection.
// So we need to setup only one redirect URI in dropbox app
// configuration (not multiple for all the tenants).
// In case deployment is running in subfolder dropbox.redirectURI
// can be configured.
const redirectURI
= dropbox.redirectURI || `${locationURL?.origin}/static/oauth.html`;
_authorizeDropbox(dropbox.appKey, redirectURI)
.then(
({ token, rToken, expireDate }) => {
dispatch(updateDropboxToken(token, rToken, expireDate));
})
.catch(error => logger.log('Cannot authorize dropbox', error));
};
}
/**
* Action to update the dropbox access token.
*
* @param {string} token - The new token.
* @param {string} rToken - The refresh token.
* @param {number} expireDate - The token expiration date as UNIX timestamp.
* @returns {{
* type: UPDATE_DROPBOX_TOKEN,
* token: string,
* rToken: string,
* expireDate: number
* }}
*/
export function updateDropboxToken(token?: string, rToken?: string, expireDate?: number) {
return {
type: UPDATE_DROPBOX_TOKEN,
token,
rToken,
expireDate
};
}

View File

@@ -0,0 +1,48 @@
export * from './functions';
import { getDisplayName, getSpaceUsage } from './functions';
import logger from './logger';
/**
* Information related to the user's dropbox account.
*/
type DropboxUserData = {
/**
* The available space left in MB into the user's Dropbox account.
*/
spaceLeft: number;
/**
* The display name of the user in Dropbox.
*/
userName: string;
};
/**
* Fetches information about the user's dropbox account.
*
* @param {string} token - The dropbox access token.
* @param {string} appKey - The Jitsi Recorder dropbox app key.
* @returns {Promise<DropboxUserData|undefined>}
*/
export function getDropboxData(
token: string,
appKey: string
): Promise<DropboxUserData | undefined> {
return Promise.all(
[ getDisplayName(token, appKey), getSpaceUsage(token, appKey) ]
).then(([ userName, space ]) => {
const { allocated, used } = space;
return {
userName,
spaceLeft: Math.floor((allocated - used) / 1048576)// 1MiB=1048576B
};
}, error => {
logger.error(error);
return undefined;
});
}

View File

@@ -0,0 +1,74 @@
import { NativeModules } from 'react-native';
import { IReduxState } from '../app/types';
import { setPictureInPictureEnabled } from '../mobile/picture-in-picture/functions';
const { Dropbox } = NativeModules;
/**
* Action to authorize the Jitsi Recording app in dropbox.
*
* @param {any} _appKey - Used on web.
* @param {any} _redirectURI - Used on web.
* @returns {Promise<Object>} - The promise will be resolved with the dropbox
* access token or rejected with an error.
*/
export async function _authorizeDropbox(_appKey?: any, _redirectURI?: any): Promise<any> {
setPictureInPictureEnabled(false);
try {
return await Dropbox.authorize();
} finally {
setPictureInPictureEnabled(true);
}
}
/**
* Gets a new access token based on the refresh token.
*
* @param {string} _appKey - The dropbox appKey.
* @param {string} _rToken - The refresh token.
* @returns {Promise}
*/
export function getNewAccessToken(_appKey: string, _rToken: string) {
return _authorizeDropbox();
}
/**
* Returns the display name for the current dropbox account.
*
* @param {string} token - The dropbox access token.
* @param {any} _appKey - Used on web.
* @returns {Promise<string>} - The promise will be resolved with the display
* name or rejected with an error.
*/
export function getDisplayName(token: string, _appKey?: any) {
return Dropbox.getDisplayName(token);
}
/**
* Returns information about the space usage for the current dropbox account.
*
* @param {string} token - The dropbox access token.
* @param {any} _appKey - Used on web.
* @returns {Promise<{ used: number, allocated: number}>} - The promise will be
* resolved with the object with information about the space usage (the used
* space and the allocated space) for the current dropbox account or rejected
* with an error.
*/
export function getSpaceUsage(token: string, _appKey?: any) {
return Dropbox.getSpaceUsage(token);
}
/**
* Returns <tt>true</tt> if the dropbox features is enabled and <tt>false</tt>
* otherwise.
*
* @param {Object} state - The redux state.
* @returns {boolean}
*/
export function isEnabled(state: IReduxState) {
const { dropbox = { appKey: undefined } } = state['features/base/config'];
return Boolean(Dropbox?.ENABLED && typeof dropbox.appKey === 'string');
}

View File

@@ -0,0 +1,152 @@
import { Dropbox, DropboxAuth } from 'dropbox';
import { IReduxState } from '../app/types';
/**
* Executes the oauth flow.
*
* @param {string} authUrl - The URL to oauth service.
* @returns {Promise<string>} - The URL with the authorization details.
*/
function authorize(authUrl: string): Promise<string> {
const windowName = `oauth${Date.now()}`;
return new Promise(resolve => {
// eslint-disable-next-line prefer-const
let popup: any;
const handleAuth = ({ data }: { data: { type: string; url: string; windowName: string; }; }) => {
if (data && data.type === 'dropbox-login' && data.windowName === windowName) {
if (popup) {
popup.close();
}
window.removeEventListener('message', handleAuth);
resolve(data.url);
}
};
window.addEventListener('message', handleAuth);
popup = window.open(authUrl, windowName);
});
}
/**
* Returns the token's expiry date as UNIX timestamp.
*
* @param {number} expiresIn - The seconds in which the token expires.
* @returns {number} - The timestamp value for the expiry date.
*/
function getTokenExpiresAtTimestamp(expiresIn: number) {
return new Date(Date.now() + (expiresIn * 1000)).getTime();
}
/**
* Action to authorize the Jitsi Recording app in dropbox.
*
* @param {string} appKey - The Jitsi Recorder dropbox app key.
* @param {string} redirectURI - The return URL.
* @returns {Promise<Object>}
*/
export function _authorizeDropbox(
appKey: string,
redirectURI: string
): Promise<any> {
const dropbox = new DropboxAuth({ clientId: appKey });
return dropbox.getAuthenticationUrl(redirectURI, undefined, 'code', 'offline', undefined, undefined, true)
// @ts-ignore
.then(authorize)
.then(returnUrl => {
const params = new URLSearchParams(new URL(returnUrl).search);
const code = params.get('code');
return dropbox.getAccessTokenFromCode(redirectURI, code ?? '');
})
.then((resp: any) => {
return {
token: resp.result.access_token,
rToken: resp.result.refresh_token,
expireDate: getTokenExpiresAtTimestamp(resp.result.expires_in)
};
});
}
/**
* Gets a new access token based on the refresh token.
*
* @param {string} appKey - The dropbox appKey.
* @param {string} rToken - The refresh token.
* @returns {Promise}
*/
export function getNewAccessToken(appKey: string, rToken: string) {
const dropbox = new DropboxAuth({ clientId: appKey });
dropbox.setRefreshToken(rToken);
return dropbox.refreshAccessToken() // @ts-ignore
.then(() => {
return {
token: dropbox.getAccessToken(),
rToken: dropbox.getRefreshToken(),
expireDate: dropbox.getAccessTokenExpiresAt().getTime()
};
});
}
/**
* Returns the display name for the current dropbox account.
*
* @param {string} token - The dropbox access token.
* @param {string} appKey - The Jitsi Recorder dropbox app key.
* @returns {Promise<string>}
*/
export function getDisplayName(token: string, appKey: string) {
const dropboxAPI = new Dropbox({
accessToken: token,
clientId: appKey
});
return (
dropboxAPI.usersGetCurrentAccount()
.then(account => account.result.name.display_name));
}
/**
* Returns information about the space usage for the current dropbox account.
*
* @param {string} token - The dropbox access token.
* @param {string} appKey - The Jitsi Recorder dropbox app key.
* @returns {Promise<Object>}
*/
export function getSpaceUsage(token: string, appKey: string) {
const dropboxAPI = new Dropbox({
accessToken: token,
clientId: appKey
});
return dropboxAPI.usersGetSpaceUsage().then(space => {
const { allocation, used } = space.result;
// @ts-ignore
const { allocated } = allocation;
return {
allocated,
used
};
});
}
/**
* Returns <tt>true</tt> if the dropbox features is enabled and <tt>false</tt>
* otherwise.
*
* @param {Object} state - The redux state.
* @returns {boolean}
*/
export function isEnabled(state: IReduxState) {
const { dropbox = { appKey: undefined } } = state['features/base/config'];
return typeof dropbox.appKey === 'string';
}

View File

@@ -0,0 +1,3 @@
import { getLogger } from '../base/logging/functions';
export default getLogger('features/dropbox');

View File

@@ -0,0 +1,34 @@
import PersistenceRegistry from '../base/redux/PersistenceRegistry';
import ReducerRegistry from '../base/redux/ReducerRegistry';
import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
/**
* The redux subtree of this feature.
*/
const STORE_NAME = 'features/dropbox';
export interface IDropboxState {
expireDate?: number;
rToken?: string;
token?: string;
}
/**
* Sets up the persistence of the feature {@code dropbox}.
*/
PersistenceRegistry.register(STORE_NAME);
ReducerRegistry.register<IDropboxState>(STORE_NAME, (state = {}, action): IDropboxState => {
switch (action.type) {
case UPDATE_DROPBOX_TOKEN:
return {
...state,
token: action.token,
rToken: action.rToken,
expireDate: action.expireDate
};
default:
return state;
}
});