Skip to content

Commit

Permalink
Merge branch 'main' into dedicated-iv-per-payload
Browse files Browse the repository at this point in the history
  • Loading branch information
stef-coenen committed Dec 13, 2023
2 parents 3578269 + 2b9607e commit e79754e
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 6 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/js-lib/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.0.2-alpha.16",
"version": "0.0.2-alpha.17",
"name": "@youfoundation/js-lib",
"author": "YouFoundation",
"description": "JavaScript SDK for the DotYouCore api",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Toast, t } from '@youfoundation/common-app';
import { useAccountRemoval } from '../../hooks/removal/useAccountRemoval';

export const CriticalOwnerAlerts = () => {
const {
status: { data: statusData },
} = useAccountRemoval();

const isScheduledForDeletion = !!statusData?.plannedDeletionDate;

if (!isScheduledForDeletion) return null;

const date = new Date(statusData.plannedDeletionDate as number);

return (
<div className="fixed bottom-2 left-2 right-2 z-50 grid grid-flow-row gap-4 sm:bottom-auto sm:left-auto sm:right-8 sm:top-8">
<Toast
type={'critical'}
title={`${t(
'Your account is scheduled for deletion'
)} ${date.toLocaleDateString()}. Click for info`}
href="/owner/settings/delete"
/>
</div>
);
};
4 changes: 4 additions & 0 deletions packages/owner-app/src/components/ui/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FC, ReactNode } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useDarkMode, Toaster, Sidenav } from '@youfoundation/common-app';
import { useAuth } from '../../../hooks/auth/useAuth';
import { CriticalOwnerAlerts } from '../../OwnerAlerts/CriticalOwnerAlerts';

interface LayoutProps {
children?: ReactNode;
Expand Down Expand Up @@ -51,6 +52,7 @@ const Layout: FC<LayoutProps> = ({ children, noShadedBg, noPadding }) => {
</div>
</div>
<Toaster />
<CriticalOwnerAlerts />
</div>
</>
);
Expand All @@ -65,6 +67,7 @@ export const MinimalLayout: FC<LayoutProps> = ({ children, noShadedBg, noPadding
<div className={`${noPadding ? '' : 'px-5 py-4 sm:px-10 sm:py-8'}`}>{children}</div>
</div>
<Toaster />
<CriticalOwnerAlerts />
</>
);
};
Expand All @@ -78,6 +81,7 @@ export const NoLayout: FC<LayoutProps> = ({ children, noShadedBg }) => {
{children}
</div>
<Toaster />
<CriticalOwnerAlerts />
</>
);
};
Expand Down
40 changes: 40 additions & 0 deletions packages/owner-app/src/hooks/removal/useAccountRemoval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDotYouClient } from '@youfoundation/common-app';
import {
accountDeletionStatus,
markAccountDeletion,
unmarkAccountDeletion,
} from '../../provider/system/RemoveProvider';

export const useAccountRemoval = () => {
const queryClient = useQueryClient();
const dotYouClient = useDotYouClient().getDotYouClient();

const getAccountDeletionStatus = async () => {
return accountDeletionStatus(dotYouClient);
};

const markDeletion = async (currentPassword: string) => {
return await markAccountDeletion(dotYouClient, currentPassword);
};

const unMarkDeletion = async (currentPassword: string) => {
return await unmarkAccountDeletion(dotYouClient, currentPassword);
};

return {
status: useQuery({ queryKey: ['removal-status'], queryFn: getAccountDeletionStatus }),
delete: useMutation({
mutationFn: markDeletion,
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['removal-status'] });
},
}),
undelete: useMutation({
mutationFn: unMarkDeletion,
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['removal-status'] });
},
}),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export const isPasswordSet = async (): Promise<boolean> => {
};

/// Internal helpers
const getNonce = async (dotYouClient: DotYouClient): Promise<NonceData> => {
export const getNonce = async (dotYouClient: DotYouClient): Promise<NonceData> => {
const client = dotYouClient.createAxiosClient({ overrideEncryption: true });
return client
.get('/authentication/nonce')
Expand Down
60 changes: 60 additions & 0 deletions packages/owner-app/src/provider/system/RemoveProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { DotYouClient, DriveDefinition, TargetDrive } from '@youfoundation/js-lib/core';
import { getNonce } from '../auth/AuthenticationProvider';
import { prepareAuthPassword } from '../auth/AuthenticationHelper';

export interface DriveDefinitionParam extends Omit<DriveDefinition, 'targetDriveInfo'> {
targetDrive: TargetDrive;
}

//Handles management of the System
const root = '/security';

//api/owner/v1/security/delete-account
export const markAccountDeletion = async (dotYouClient: DotYouClient, currentPassword: string) => {
const noncePackage = await getNonce(dotYouClient);
const currentAuthenticationPasswordReply = await prepareAuthPassword(
currentPassword,
noncePackage
);

const client = dotYouClient.createAxiosClient();
const url = root + '/delete-account';

return client.post(url, { currentAuthenticationPasswordReply }).then((response) => {
return response.status === 200;
});
};

//api/owner/v1/security/undelete-account
export const unmarkAccountDeletion = async (
dotYouClient: DotYouClient,
currentPassword: string
) => {
const noncePackage = await getNonce(dotYouClient);
const currentAuthenticationPasswordReply = await prepareAuthPassword(
currentPassword,
noncePackage
);

const client = dotYouClient.createAxiosClient();
const url = root + '/undelete-account';

return client.post(url, { currentAuthenticationPasswordReply }).then((response) => {
return response.status === 200;
});
};

//api/owner/v1/security/account-status
export const accountDeletionStatus = async (dotYouClient: DotYouClient) => {
const client = dotYouClient.createAxiosClient();
const url = root + '/account-status';

return client.get<AccountDeletionStatus>(url).then((response) => {
return response.data;
});
};

export interface AccountDeletionStatus {
plannedDeletionDate?: number;
planId: string;
}
116 changes: 116 additions & 0 deletions packages/owner-app/src/templates/Settings/DeleteAccountSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { t, Alert, ActionButton, Label, Input } from '@youfoundation/common-app';
import { useEffect, useState } from 'react';
import Section from '../../components/ui/Sections/Section';
import { useAccountRemoval } from '../../hooks/removal/useAccountRemoval';

export const DeleteAccountSettings = () => {
const [currentPassword, setCurrentPassword] = useState('');
const {
status: { data: statusData },
delete: { mutate: deleteAccount, status: deleteStatus },
undelete: { mutate: undeleteAccount, status: undeleteStatus },
} = useAccountRemoval();

const isScheduledForDeletion = !!statusData?.plannedDeletionDate;
useEffect(() => setCurrentPassword(''), [deleteStatus, undeleteStatus]);

if (isScheduledForDeletion) {
const scheduledDate = new Date(statusData.plannedDeletionDate as number);
return (
<>
<Alert type="critical" className="mb-5">
{t('Your account is scheduled for deletion on')} {scheduledDate.toLocaleDateString()}
</Alert>
<Section title={t('Cancel delete account')}>
<p className="mb-5 max-w-lg text-slate-400">
{t('Would you like to cancel the deletion of your account? You can do so until')}{' '}
{scheduledDate.toLocaleDateString()}
</p>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();

if (e.currentTarget.reportValidity()) undeleteAccount(currentPassword);
}}
>
<div className="mb-2">
<Label>{t('Your password')}</Label>
<Input
required
name="currentPassowrd"
id="currentPassowrd"
type="password"
onChange={(e) => setCurrentPassword(e.target.value)}
defaultValue={currentPassword}
autoComplete="current-password"
/>
</div>
<div className="mt-5 flex flex-row-reverse">
<ActionButton
confirmOptions={{
title: t('Cancel the deletion of your account'),
body: t('Are you sure you want to cancel the deletion of your account?'),
buttonText: t('Cancel delete account'),
}}
state={undeleteStatus}
isDisabled={!currentPassword}
onClick={() => undeleteAccount(currentPassword)}
>
{t('Cancel delete account')}
</ActionButton>
</div>
</form>
</Section>
</>
);
} else {
return (
<>
<Section title={t('Delete account')}>
<p className="mb-5 max-w-lg text-slate-400">
{t(
`If you want to delete you account, you can request account deletion below.
Once requested, you account will be scheduled for deletion after 30 days.
In that time you will be able to cancel the request.`
)}
</p>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
if (e.currentTarget.reportValidity()) deleteAccount(currentPassword);
}}
>
<div className="mb-2">
<Label>{t('Your password')}</Label>
<Input
required
name="currentPassowrd"
id="currentPassowrd"
type="password"
onChange={(e) => setCurrentPassword(e.target.value)}
defaultValue={currentPassword}
autoComplete="current-password"
/>
</div>
<div className="mt-5 flex flex-row-reverse">
<ActionButton
confirmOptions={{
title: t('Delete account'),
body: t('Are you sure you want to delete your account?'),
buttonText: t('Delete account'),
}}
state={deleteStatus}
isDisabled={!currentPassword}
onClick={() => deleteAccount(currentPassword)}
>
{t('Delete account')}
</ActionButton>
</div>
</form>
</Section>
</>
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ export const SecuritySettings = () => {
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
doSetNewPassword();

if (e.currentTarget.reportValidity()) {
doSetNewPassword();
}
}}
>
<div className="mb-2">
Expand Down
6 changes: 6 additions & 0 deletions packages/owner-app/src/templates/Settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useParams } from 'react-router-dom';
import { NetworkVisibilitySettings } from './NetworkVisibilitySettings';
import { ReactionSettings } from './ReactionSettings';
import { SecuritySettings } from './SecuritySettings';
import { DeleteAccountSettings } from './DeleteAccountSettings';

const Settings = () => {
const { sectionId } = useParams();
Expand All @@ -27,12 +28,17 @@ const Settings = () => {
title: `Security`,
path: `/owner/settings/security`,
},
{
title: `Delete`,
path: `/owner/settings/delete`,
},
]}
className="-mt-6 mb-4"
/>
{(sectionId === 'privacy' || !sectionId) && <NetworkVisibilitySettings />}
{sectionId === 'reactions' && <ReactionSettings />}
{sectionId === 'security' && <SecuritySettings />}
{sectionId === 'delete' && <DeleteAccountSettings />}
</>
);
};
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-lib/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.0.2-alpha.8",
"version": "0.0.2-alpha.9",
"name": "@youfoundation/ui-lib",
"author": "YouFoundation",
"description": "UI-Lib for DotYouCore",
Expand Down

0 comments on commit e79754e

Please sign in to comment.