diff options
author | Samuel Newman <mozzius@protonmail.com> | 2024-05-24 00:10:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-23 16:10:13 -0700 |
commit | d2c42cf16905a8904dcfbba4825ca5f8abc3f253 (patch) | |
tree | b7a46c68b714b7eaa3c938387617f4174b6c1924 | |
parent | 406993cf0e5d5fee2bac75aacc528da12c4e0289 (diff) | |
download | voidsky-d2c42cf16905a8904dcfbba4825ca5f8abc3f253.tar.zst |
Privileged app passwords (#4200)
* add checkbox to create privileged app password * add indicator to privileged app pwds to list * bump api * oops missed the yarnlock * adjust modal padding * lowercase * one more lowercase --------- Co-authored-by: Hailey <me@haileyok.com>
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/state/queries/app-passwords.ts | 5 | ||||
-rw-r--r-- | src/view/com/modals/AddAppPasswords.tsx | 179 | ||||
-rw-r--r-- | src/view/screens/AppPasswords.tsx | 53 | ||||
-rw-r--r-- | yarn.lock | 8 |
5 files changed, 141 insertions, 106 deletions
diff --git a/package.json b/package.json index 2680b2d1b..4c79e29f9 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web" }, "dependencies": { - "@atproto/api": "^0.12.11", + "@atproto/api": "^0.12.13", "@bam.tech/react-native-image-resizer": "^3.0.4", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", diff --git a/src/state/queries/app-passwords.ts b/src/state/queries/app-passwords.ts index a8f8fba0f..33009a3a4 100644 --- a/src/state/queries/app-passwords.ts +++ b/src/state/queries/app-passwords.ts @@ -25,12 +25,13 @@ export function useAppPasswordCreateMutation() { return useMutation< ComAtprotoServerCreateAppPassword.OutputSchema, Error, - {name: string} + {name: string; privileged: boolean} >({ - mutationFn: async ({name}) => { + mutationFn: async ({name, privileged}) => { return ( await getAgent().com.atproto.server.createAppPassword({ name, + privileged, }) ).data }, diff --git a/src/view/com/modals/AddAppPasswords.tsx b/src/view/com/modals/AddAppPasswords.tsx index e6f424ed0..d6df12657 100644 --- a/src/view/com/modals/AddAppPasswords.tsx +++ b/src/view/com/modals/AddAppPasswords.tsx @@ -8,20 +8,23 @@ import { import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {usePalette} from '#/lib/hooks/usePalette' +import {s} from '#/lib/styles' import {logger} from '#/logger' +import {isNative} from '#/platform/detection' import {useModalControls} from '#/state/modals' import { useAppPasswordCreateMutation, useAppPasswordsQuery, } from '#/state/queries/app-passwords' -import {usePalette} from 'lib/hooks/usePalette' -import {s} from 'lib/styles' -import {isNative} from 'platform/detection' -import {Button} from '../util/forms/Button' -import {Text} from '../util/text/Text' -import * as Toast from '../util/Toast' +import {Button} from '#/view/com/util/forms/Button' +import {Text} from '#/view/com/util/text/Text' +import * as Toast from '#/view/com/util/Toast' +import {atoms as a} from '#/alf' +import * as Toggle from '#/components/forms/Toggle' +import {KeyboardPadding} from '#/components/KeyboardPadding' -export const snapPoints = ['70%'] +export const snapPoints = ['90%'] const shadesOfBlue: string[] = [ 'AliceBlue', @@ -70,6 +73,7 @@ export function Component({}: {}) { ) const [appPassword, setAppPassword] = useState<string>() const [wasCopied, setWasCopied] = useState(false) + const [privileged, setPrivileged] = useState(false) const onCopy = React.useCallback(() => { if (appPassword) { @@ -109,7 +113,7 @@ export function Component({}: {}) { } try { - const newPassword = await mutateAppPassword({name}) + const newPassword = await mutateAppPassword({name, privileged}) if (newPassword) { setAppPassword(newPassword.password) } else { @@ -140,86 +144,98 @@ export function Component({}: {}) { return ( <View style={[styles.container, pal.view]} testID="addAppPasswordsModal"> - <View> - {!appPassword ? ( - <Text type="lg" style={[pal.text]}> + {!appPassword ? ( + <> + <View> + <Text type="lg" style={[pal.text]}> + <Trans> + Please enter a unique name for this App Password or use our + randomly generated one. + </Trans> + </Text> + <View style={[pal.btn, styles.textInputWrapper]}> + <TextInput + style={[styles.input, pal.text]} + onChangeText={_onChangeText} + value={name} + placeholder={_(msg`Enter a name for this App Password`)} + placeholderTextColor={pal.colors.textLight} + autoCorrect={false} + autoComplete="off" + autoCapitalize="none" + autoFocus={true} + maxLength={32} + selectTextOnFocus={true} + blurOnSubmit={true} + editable={!isPending} + returnKeyType="done" + onSubmitEditing={createAppPassword} + accessible={true} + accessibilityLabel={_(msg`Name`)} + accessibilityHint={_(msg`Input name for app password`)} + /> + </View> + </View> + <Text type="xs" style={[pal.textLight, s.mb10, s.mt2]}> <Trans> - Please enter a unique name for this App Password or use our - randomly generated one. + Can only contain letters, numbers, spaces, dashes, and + underscores. Must be at least 4 characters long, but no more than + 32 characters long. </Trans> </Text> - ) : ( - <Text type="lg" style={[pal.text]}> - <Text type="lg-bold" style={[pal.text, s.mr5]}> - <Trans>Here is your app password.</Trans> + <Toggle.Item + type="checkbox" + label={_(msg`Allow access to your direct messages`)} + value={privileged} + onChange={val => setPrivileged(val)} + name="privileged" + style={a.my_md}> + <Toggle.Checkbox /> + <Toggle.LabelText> + <Trans>Allow access to your direct messages</Trans> + </Toggle.LabelText> + </Toggle.Item> + </> + ) : ( + <> + <View> + <Text type="lg" style={[pal.text]}> + <Text type="lg-bold" style={[pal.text, s.mr5]}> + <Trans>Here is your app password.</Trans> + </Text> + <Trans> + Use this to sign into the other app along with your handle. + </Trans> </Text> + <TouchableOpacity + style={[pal.border, styles.passwordContainer, pal.btn]} + onPress={onCopy} + accessibilityRole="button" + accessibilityLabel={_(msg`Copy`)} + accessibilityHint={_(msg`Copies app password`)}> + <Text type="2xl-bold" style={[pal.text]}> + {appPassword} + </Text> + {wasCopied ? ( + <Text style={[pal.textLight]}> + <Trans>Copied</Trans> + </Text> + ) : ( + <FontAwesomeIcon + icon={['far', 'clone']} + style={pal.text as FontAwesomeIconStyle} + size={18} + /> + )} + </TouchableOpacity> + </View> + <Text type="lg" style={[pal.textLight, s.mb10]}> <Trans> - Use this to sign into the other app along with your handle. + For security reasons, you won't be able to view this again. If you + lose this password, you'll need to generate a new one. </Trans> </Text> - )} - {!appPassword ? ( - <View style={[pal.btn, styles.textInputWrapper]}> - <TextInput - style={[styles.input, pal.text]} - onChangeText={_onChangeText} - value={name} - placeholder={_(msg`Enter a name for this App Password`)} - placeholderTextColor={pal.colors.textLight} - autoCorrect={false} - autoComplete="off" - autoCapitalize="none" - autoFocus={true} - maxLength={32} - selectTextOnFocus={true} - blurOnSubmit={true} - editable={!isPending} - returnKeyType="done" - onSubmitEditing={createAppPassword} - accessible={true} - accessibilityLabel={_(msg`Name`)} - accessibilityHint={_(msg`Input name for app password`)} - /> - </View> - ) : ( - <TouchableOpacity - style={[pal.border, styles.passwordContainer, pal.btn]} - onPress={onCopy} - accessibilityRole="button" - accessibilityLabel={_(msg`Copy`)} - accessibilityHint={_(msg`Copies app password`)}> - <Text type="2xl-bold" style={[pal.text]}> - {appPassword} - </Text> - {wasCopied ? ( - <Text style={[pal.textLight]}> - <Trans>Copied</Trans> - </Text> - ) : ( - <FontAwesomeIcon - icon={['far', 'clone']} - style={pal.text as FontAwesomeIconStyle} - size={18} - /> - )} - </TouchableOpacity> - )} - </View> - {appPassword ? ( - <Text type="lg" style={[pal.textLight, s.mb10]}> - <Trans> - For security reasons, you won't be able to view this again. If you - lose this password, you'll need to generate a new one. - </Trans> - </Text> - ) : ( - <Text type="xs" style={[pal.textLight, s.mb10, s.mt2]}> - <Trans> - Can only contain letters, numbers, spaces, dashes, and underscores. - Must be at least 4 characters long, but no more than 32 characters - long. - </Trans> - </Text> + </> )} <View style={styles.btnContainer}> <Button @@ -230,6 +246,7 @@ export function Component({}: {}) { onPress={!appPassword ? createAppPassword : onDone} /> </View> + <KeyboardPadding /> </View> ) } diff --git a/src/view/screens/AppPasswords.tsx b/src/view/screens/AppPasswords.tsx index 800216169..65cbb7374 100644 --- a/src/view/screens/AppPasswords.tsx +++ b/src/view/screens/AppPasswords.tsx @@ -5,32 +5,34 @@ import { TouchableOpacity, View, } from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {ScrollView} from 'react-native-gesture-handler' -import {Text} from '../com/util/text/Text' -import {Button} from '../com/util/forms/Button' -import * as Toast from '../com/util/Toast' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {NativeStackScreenProps} from '@react-navigation/native-stack' -import {CommonNavigatorParams} from 'lib/routes/types' -import {useAnalytics} from 'lib/analytics/analytics' -import {useFocusEffect} from '@react-navigation/native' -import {ViewHeader} from '../com/util/ViewHeader' -import {CenteredView} from 'view/com/util/Views' -import {Trans, msg} from '@lingui/macro' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useSetMinimalShellMode} from '#/state/shell' +import {useFocusEffect} from '@react-navigation/native' +import {NativeStackScreenProps} from '@react-navigation/native-stack' + +import {useAnalytics} from '#/lib/analytics/analytics' +import {usePalette} from '#/lib/hooks/usePalette' +import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' +import {CommonNavigatorParams} from '#/lib/routes/types' +import {cleanError} from '#/lib/strings/errors' import {useModalControls} from '#/state/modals' import {useLanguagePrefs} from '#/state/preferences' import { - useAppPasswordsQuery, useAppPasswordDeleteMutation, + useAppPasswordsQuery, } from '#/state/queries/app-passwords' -import {ErrorScreen} from '../com/util/error/ErrorScreen' -import {cleanError} from '#/lib/strings/errors' -import * as Prompt from '#/components/Prompt' +import {useSetMinimalShellMode} from '#/state/shell' +import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' +import {Button} from '#/view/com/util/forms/Button' +import {Text} from '#/view/com/util/text/Text' +import * as Toast from '#/view/com/util/Toast' +import {ViewHeader} from '#/view/com/util/ViewHeader' +import {CenteredView} from 'view/com/util/Views' +import {atoms as a} from '#/alf' import {useDialogControl} from '#/components/Dialog' +import * as Prompt from '#/components/Prompt' type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'> export function AppPasswords({}: Props) { @@ -135,6 +137,7 @@ export function AppPasswords({}: Props) { testID={`appPassword-${i}`} name={password.name} createdAt={password.createdAt} + privileged={password.privileged} /> ))} {isTabletOrDesktop && ( @@ -207,10 +210,12 @@ function AppPassword({ testID, name, createdAt, + privileged, }: { testID: string name: string createdAt: string + privileged?: boolean }) { const pal = usePalette('default') const {_} = useLingui() @@ -255,6 +260,18 @@ function AppPassword({ }).format(new Date(createdAt))} </Trans> </Text> + {privileged && ( + <View style={[a.flex_row, a.gap_sm, a.align_center, a.mt_xs]}> + <FontAwesomeIcon + icon="circle-exclamation" + color={pal.colors.textLight} + size={14} + /> + <Text type="md" style={pal.textLight}> + Allows access to direct messages + </Text> + </View> + )} </View> <FontAwesomeIcon icon={['far', 'trash-can']} style={styles.trashIcon} /> diff --git a/yarn.lock b/yarn.lock index c7dc9e342..96bd60b7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,10 +34,10 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@atproto/api@^0.12.11": - version "0.12.11" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.11.tgz#d117a0c81395153289e99bafa760a05c2836896f" - integrity sha512-NABsZ4ZYznWisr1bGuP6Z4X1GTiu5gNrmAQTxWp45M8RX88BFP1PskoG3J42d2iiyQMVBwTdoENTFYzvsKBuQg== +"@atproto/api@^0.12.13": + version "0.12.13" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.13.tgz#269d6c57ea894e23f20b28bd3cbfed944bd28528" + integrity sha512-pRSID6w8AUiZJoCxgctMPRTSGVFHq7wphAnxEbRLBP3OQ1g+BRZUcqFw+e+17Pd3wrc8VImjiD4HCWtCJvCx3w== dependencies: "@atproto/common-web" "^0.3.0" "@atproto/lexicon" "^0.4.0" |