diff --git a/lib/types/keyserver-types.js b/lib/types/keyserver-types.js index 317681356..5910a98be 100644 --- a/lib/types/keyserver-types.js +++ b/lib/types/keyserver-types.js @@ -1,55 +1,71 @@ // @flow import t, { type TInterface } from 'tcomb'; import type { PlatformDetails } from './device-types.js'; -import { connectionInfoValidator } from './socket-types.js'; -import type { ConnectionInfo } from './socket-types.js'; +import { + type ConnectionInfo, + connectionInfoValidator, + defaultConnectionInfo, +} from './socket-types.js'; import type { GlobalAccountUserInfo } from './user-types.js'; import { tShape, tPlatformDetails } from '../utils/validation-utils.js'; export type KeyserverInfo = { +cookie: ?string, +sessionID?: ?string, +updatesCurrentAsOf: number, // millisecond timestamp +urlPrefix: string, +connection: ConnectionInfo, +lastCommunicatedPlatformDetails: ?PlatformDetails, +deviceToken: ?string, }; +const defaultKeyserverInfo: ( + urlPrefix: string, +) => KeyserverInfo = urlPrefix => ({ + cookie: null, + updatesCurrentAsOf: 0, + urlPrefix, + connection: defaultConnectionInfo, + lastCommunicatedPlatformDetails: null, + deviceToken: null, +}); + export type KeyserverInfos = { +[key: string]: KeyserverInfo }; export type KeyserverStore = { +keyserverInfos: KeyserverInfos, }; export type SelectedKeyserverInfo = { +keyserverAdminUserInfo: GlobalAccountUserInfo, +keyserverInfo: KeyserverInfo, }; export type AddKeyserverPayload = { +keyserverAdminUserID: string, +newKeyserverInfo: KeyserverInfo, }; export type RemoveKeyserverPayload = { +keyserverAdminUserID: string, }; export const keyserverInfoValidator: TInterface = tShape({ cookie: t.maybe(t.String), sessionID: t.maybe(t.String), updatesCurrentAsOf: t.Number, urlPrefix: t.String, connection: connectionInfoValidator, lastCommunicatedPlatformDetails: t.maybe(tPlatformDetails), deviceToken: t.maybe(t.String), }); export const keyserverStoreValidator: TInterface = tShape({ keyserverInfos: t.dict(t.String, keyserverInfoValidator), }); + +export { defaultKeyserverInfo }; diff --git a/native/profile/add-keyserver.react.js b/native/profile/add-keyserver.react.js index 2316bac8f..441615e1f 100644 --- a/native/profile/add-keyserver.react.js +++ b/native/profile/add-keyserver.react.js @@ -1,160 +1,153 @@ // @flow import { useNavigation } from '@react-navigation/native'; import * as React from 'react'; import { View, Text } from 'react-native'; import { addKeyserverActionType } from 'lib/actions/keyserver-actions.js'; import { useIsKeyserverURLValid } from 'lib/shared/keyserver-utils.js'; import type { KeyserverInfo } from 'lib/types/keyserver-types.js'; -import { defaultConnectionInfo } from 'lib/types/socket-types.js'; +import { defaultKeyserverInfo } from 'lib/types/keyserver-types.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import type { ProfileNavigationProp } from './profile.react.js'; import TextInput from '../components/text-input.react.js'; import HeaderRightTextButton from '../navigation/header-right-text-button.react.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { useSelector } from '../redux/redux-utils.js'; import { useStyles, useColors } from '../themes/colors.js'; import { useStaffCanSee } from '../utils/staff-utils.js'; type Props = { +navigation: ProfileNavigationProp<'AddKeyserver'>, +route: NavigationRoute<'AddKeyserver'>, }; // eslint-disable-next-line no-unused-vars function AddKeyserver(props: Props): React.Node { const { goBack, setOptions } = useNavigation(); const dispatch = useDispatch(); const staffCanSee = useStaffCanSee(); const currentUserID = useSelector(state => state.currentUserInfo?.id); const customServer = useSelector(state => state.customServer); const { panelForegroundTertiaryLabel } = useColors(); const styles = useStyles(unboundStyles); const [urlInput, setUrlInput] = React.useState( customServer && staffCanSee ? customServer : '', ); const [showErrorMessage, setShowErrorMessage] = React.useState(false); const isKeyserverURLValidCallback = useIsKeyserverURLValid(urlInput); const onPressSave = React.useCallback(async () => { setShowErrorMessage(false); if (!currentUserID || !urlInput) { return; } const isKeyserverURLValid = await isKeyserverURLValidCallback(); if (!isKeyserverURLValid) { setShowErrorMessage(true); return; } - const newKeyserverInfo: KeyserverInfo = { - cookie: null, - updatesCurrentAsOf: 0, - urlPrefix: urlInput, - connection: defaultConnectionInfo, - lastCommunicatedPlatformDetails: null, - deviceToken: null, - }; + const newKeyserverInfo: KeyserverInfo = defaultKeyserverInfo(urlInput); dispatch({ type: addKeyserverActionType, payload: { keyserverAdminUserID: currentUserID, newKeyserverInfo, }, }); goBack(); }, [currentUserID, dispatch, goBack, isKeyserverURLValidCallback, urlInput]); React.useEffect(() => { setOptions({ headerRight: () => ( ), }); }, [onPressSave, setOptions, styles.header]); const onChangeText = React.useCallback( (text: string) => setUrlInput(text), [], ); const errorMessage = React.useMemo(() => { if (!showErrorMessage) { return null; } return ( Cannot connect to keyserver. Please check the URL or your connection and try again. ); }, [showErrorMessage, styles.errorMessage]); return ( KEYSERVER URL {errorMessage} ); } const unboundStyles = { container: { paddingTop: 8, }, header: { color: 'panelBackgroundLabel', fontSize: 12, fontWeight: '400', paddingBottom: 3, paddingHorizontal: 24, }, inputContainer: { backgroundColor: 'panelForeground', flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 24, paddingVertical: 12, borderBottomWidth: 1, borderColor: 'panelForegroundBorder', borderTopWidth: 1, }, input: { color: 'panelForegroundLabel', flex: 1, fontFamily: 'Arial', fontSize: 16, paddingVertical: 0, borderBottomColor: 'transparent', }, errorMessage: { marginTop: 8, marginHorizontal: 16, color: 'redText', }, }; export default AddKeyserver; diff --git a/native/redux/default-state.js b/native/redux/default-state.js index ce157bad0..40c86998e 100644 --- a/native/redux/default-state.js +++ b/native/redux/default-state.js @@ -1,92 +1,85 @@ // @flow import { Platform } from 'react-native'; import Orientation from 'react-native-orientation-locker'; import { defaultEnabledApps } from 'lib/types/enabled-apps.js'; import { defaultCalendarQuery } from 'lib/types/entry-types.js'; import { defaultCalendarFilters } from 'lib/types/filter-types.js'; -import { defaultConnectionInfo } from 'lib/types/socket-types.js'; +import { defaultKeyserverInfo } from 'lib/types/keyserver-types.js'; import { defaultGlobalThemeInfo } from 'lib/types/theme-types.js'; import { defaultNotifPermissionAlertInfo } from 'lib/utils/push-alerts.js'; import { ashoatKeyserverID } from 'lib/utils/validation-utils.js'; import { defaultDimensionsInfo } from './dimensions-updater.react.js'; import type { AppState } from './state-types.js'; import { defaultNavInfo } from '../navigation/default-state.js'; import { defaultDeviceCameraInfo } from '../types/camera.js'; import { defaultConnectivityInfo } from '../types/connectivity.js'; import { defaultURLPrefix, natNodeServer } from '../utils/url-utils.js'; const defaultState = ({ navInfo: defaultNavInfo, currentUserInfo: null, draftStore: { drafts: {} }, entryStore: { entryInfos: {}, daysToEntries: {}, lastUserInteractionCalendar: 0, }, threadStore: { threadInfos: {}, }, userStore: { userInfos: {}, }, messageStore: { messages: {}, threads: {}, local: {}, currentAsOf: { [ashoatKeyserverID]: 0 }, }, storeLoaded: false, loadingStatuses: {}, calendarFilters: defaultCalendarFilters, dataLoaded: false, customServer: natNodeServer, notifPermissionAlertInfo: defaultNotifPermissionAlertInfo, actualizedCalendarQuery: defaultCalendarQuery(Platform.OS), watchedThreadIDs: [], lifecycleState: 'active', enabledApps: defaultEnabledApps, reportStore: { enabledReports: { crashReports: __DEV__, inconsistencyReports: __DEV__, mediaReports: __DEV__, }, queuedReports: [], }, nextLocalID: 0, _persist: null, dimensions: defaultDimensionsInfo, connectivity: defaultConnectivityInfo, globalThemeInfo: defaultGlobalThemeInfo, deviceCameraInfo: defaultDeviceCameraInfo, deviceOrientation: Orientation.getInitialOrientation(), frozen: false, userPolicies: {}, commServicesAccessToken: null, inviteLinksStore: { links: {}, }, keyserverStore: { keyserverInfos: { - [ashoatKeyserverID]: { - cookie: null, - updatesCurrentAsOf: 0, - urlPrefix: defaultURLPrefix, - connection: defaultConnectionInfo, - lastCommunicatedPlatformDetails: null, - deviceToken: null, - }, + [ashoatKeyserverID]: defaultKeyserverInfo(defaultURLPrefix), }, }, localSettings: { isBackupEnabled: false, }, threadActivityStore: {}, integrityStore: { threadHashes: {}, threadHashingStatus: 'starting' }, }: AppState); export { defaultState }; diff --git a/web/modals/keyserver-selection/add-keyserver-modal.react.js b/web/modals/keyserver-selection/add-keyserver-modal.react.js index 95fc0cf72..733205c60 100644 --- a/web/modals/keyserver-selection/add-keyserver-modal.react.js +++ b/web/modals/keyserver-selection/add-keyserver-modal.react.js @@ -1,132 +1,125 @@ // @flow import * as React from 'react'; import { addKeyserverActionType } from 'lib/actions/keyserver-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { useIsKeyserverURLValid } from 'lib/shared/keyserver-utils.js'; import type { KeyserverInfo } from 'lib/types/keyserver-types.js'; -import { defaultConnectionInfo } from 'lib/types/socket-types.js'; +import { defaultKeyserverInfo } from 'lib/types/keyserver-types.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import css from './add-keyserver-modal.css'; import Button, { buttonThemes } from '../../components/button.react.js'; import { useSelector } from '../../redux/redux-utils.js'; import { useStaffCanSee } from '../../utils/staff-utils.js'; import Input from '../input.react.js'; import Modal from '../modal.react.js'; function AddKeyserverModal(): React.Node { const { popModal } = useModalContext(); const dispatch = useDispatch(); const staffCanSee = useStaffCanSee(); const currentUserID = useSelector(state => state.currentUserInfo?.id); const customServer = useSelector(state => state.customServer); const [keyserverURL, setKeyserverURL] = React.useState( customServer && staffCanSee ? customServer : '', ); const [showErrorMessage, setShowErrorMessage] = React.useState(false); const onChangeKeyserverURL = React.useCallback( (event: SyntheticEvent) => setKeyserverURL(event.currentTarget.value), [], ); const isKeyserverURLValidCallback = useIsKeyserverURLValid(keyserverURL); const onClickAddKeyserver = React.useCallback(async () => { setShowErrorMessage(false); if (!currentUserID || !keyserverURL) { return; } const isKeyserverURLValid = await isKeyserverURLValidCallback(); if (!isKeyserverURLValid) { setShowErrorMessage(true); return; } - const newKeyserverInfo: KeyserverInfo = { - cookie: null, - updatesCurrentAsOf: 0, - urlPrefix: keyserverURL, - connection: defaultConnectionInfo, - lastCommunicatedPlatformDetails: null, - deviceToken: null, - }; + const newKeyserverInfo: KeyserverInfo = defaultKeyserverInfo(keyserverURL); dispatch({ type: addKeyserverActionType, payload: { keyserverAdminUserID: currentUserID, newKeyserverInfo, }, }); popModal(); }, [ currentUserID, dispatch, keyserverURL, popModal, isKeyserverURLValidCallback, ]); const errorMessage = React.useMemo(() => { if (!showErrorMessage) { return null; } return (
Cannot connect to keyserver. Please check the URL or your connection and try again.
); }, [showErrorMessage]); const addKeyserverModal = React.useMemo( () => (
Keyserver URL
{errorMessage}
), [ errorMessage, keyserverURL, onChangeKeyserverURL, onClickAddKeyserver, popModal, ], ); return addKeyserverModal; } export default AddKeyserverModal; diff --git a/web/redux/default-state.js b/web/redux/default-state.js index f25701548..98c6082e2 100644 --- a/web/redux/default-state.js +++ b/web/redux/default-state.js @@ -1,91 +1,84 @@ // @flow import { defaultWebEnabledApps } from 'lib/types/enabled-apps.js'; import { defaultCalendarFilters } from 'lib/types/filter-types.js'; -import { defaultConnectionInfo } from 'lib/types/socket-types.js'; +import { defaultKeyserverInfo } from 'lib/types/keyserver-types.js'; import { defaultGlobalThemeInfo } from 'lib/types/theme-types.js'; import { defaultNotifPermissionAlertInfo } from 'lib/utils/push-alerts.js'; import { ashoatKeyserverID } from 'lib/utils/validation-utils.js'; import type { AppState } from './redux-setup.js'; declare var keyserverURL: string; const defaultWebState: AppState = Object.freeze({ navInfo: { activeChatThreadID: null, startDate: '', endDate: '', tab: 'chat', }, currentUserInfo: null, draftStore: { drafts: {} }, entryStore: { entryInfos: {}, daysToEntries: {}, lastUserInteractionCalendar: 0, }, threadStore: { threadInfos: {}, }, userStore: { userInfos: {}, }, messageStore: { messages: {}, threads: {}, local: {}, currentAsOf: { [ashoatKeyserverID]: 0 }, }, windowActive: true, pushApiPublicKey: null, cryptoStore: null, windowDimensions: { width: window.width, height: window.height }, loadingStatuses: {}, calendarFilters: defaultCalendarFilters, dataLoaded: false, notifPermissionAlertInfo: defaultNotifPermissionAlertInfo, watchedThreadIDs: [], lifecycleState: 'active', enabledApps: defaultWebEnabledApps, reportStore: { enabledReports: { crashReports: false, inconsistencyReports: false, mediaReports: false, }, queuedReports: [], }, nextLocalID: 0, _persist: null, userPolicies: {}, commServicesAccessToken: null, inviteLinksStore: { links: {}, }, actualizedCalendarQuery: { startDate: '', endDate: '', filters: defaultCalendarFilters, }, communityPickerStore: { chat: null, calendar: null }, keyserverStore: { keyserverInfos: { - [ashoatKeyserverID]: { - cookie: null, - updatesCurrentAsOf: 0, - urlPrefix: keyserverURL, - connection: { ...defaultConnectionInfo }, - lastCommunicatedPlatformDetails: null, - deviceToken: null, - }, + [ashoatKeyserverID]: defaultKeyserverInfo(keyserverURL), }, }, threadActivityStore: {}, initialStateLoaded: false, integrityStore: { threadHashes: {}, threadHashingStatus: 'starting' }, globalThemeInfo: defaultGlobalThemeInfo, customServer: null, }); export { defaultWebState };