Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion webnext/src/pages/PasswordForm/PasswordFormPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export const PasswordFormPage = () => {
<field.FormInput
mapError={mapPasswordFieldError}
label={m.password_form_labels_password()}
type="password"
required
/>
)}
Expand All @@ -178,7 +179,11 @@ export const PasswordFormPage = () => {
}}
>
{(field) => (
<field.FormInput label={m.password_form_labels_repeat()} required />
<field.FormInput
label={m.password_form_labels_repeat()}
type="password"
required
/>
)}
</form.AppField>
<CheckList form={form} />
Expand Down
21 changes: 21 additions & 0 deletions webnext/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Route as IndexRouteImport } from './routes/index'
import { Route as PasswordIndexRouteImport } from './routes/password/index'
import { Route as PasswordSentRouteImport } from './routes/password/sent'
import { Route as PasswordFinishRouteImport } from './routes/password/finish'
import { Route as OpenidCallbackRouteImport } from './routes/openid/callback'

const TestRoute = TestRouteImport.update({
id: '/test',
Expand Down Expand Up @@ -64,6 +65,11 @@ const PasswordFinishRoute = PasswordFinishRouteImport.update({
path: '/password/finish',
getParentRoute: () => rootRouteImport,
} as any)
const OpenidCallbackRoute = OpenidCallbackRouteImport.update({
id: '/openid/callback',
path: '/openid/callback',
getParentRoute: () => rootRouteImport,
} as any)

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
Expand All @@ -72,6 +78,7 @@ export interface FileRoutesByFullPath {
'/enrollment-start': typeof EnrollmentStartRoute
'/password-reset': typeof PasswordResetRoute
'/test': typeof TestRoute
'/openid/callback': typeof OpenidCallbackRoute
'/password/finish': typeof PasswordFinishRoute
'/password/sent': typeof PasswordSentRoute
'/password': typeof PasswordIndexRoute
Expand All @@ -83,6 +90,7 @@ export interface FileRoutesByTo {
'/enrollment-start': typeof EnrollmentStartRoute
'/password-reset': typeof PasswordResetRoute
'/test': typeof TestRoute
'/openid/callback': typeof OpenidCallbackRoute
'/password/finish': typeof PasswordFinishRoute
'/password/sent': typeof PasswordSentRoute
'/password': typeof PasswordIndexRoute
Expand All @@ -95,6 +103,7 @@ export interface FileRoutesById {
'/enrollment-start': typeof EnrollmentStartRoute
'/password-reset': typeof PasswordResetRoute
'/test': typeof TestRoute
'/openid/callback': typeof OpenidCallbackRoute
'/password/finish': typeof PasswordFinishRoute
'/password/sent': typeof PasswordSentRoute
'/password/': typeof PasswordIndexRoute
Expand All @@ -108,6 +117,7 @@ export interface FileRouteTypes {
| '/enrollment-start'
| '/password-reset'
| '/test'
| '/openid/callback'
| '/password/finish'
| '/password/sent'
| '/password'
Expand All @@ -119,6 +129,7 @@ export interface FileRouteTypes {
| '/enrollment-start'
| '/password-reset'
| '/test'
| '/openid/callback'
| '/password/finish'
| '/password/sent'
| '/password'
Expand All @@ -130,6 +141,7 @@ export interface FileRouteTypes {
| '/enrollment-start'
| '/password-reset'
| '/test'
| '/openid/callback'
| '/password/finish'
| '/password/sent'
| '/password/'
Expand All @@ -142,6 +154,7 @@ export interface RootRouteChildren {
EnrollmentStartRoute: typeof EnrollmentStartRoute
PasswordResetRoute: typeof PasswordResetRoute
TestRoute: typeof TestRoute
OpenidCallbackRoute: typeof OpenidCallbackRoute
PasswordFinishRoute: typeof PasswordFinishRoute
PasswordSentRoute: typeof PasswordSentRoute
PasswordIndexRoute: typeof PasswordIndexRoute
Expand Down Expand Up @@ -212,6 +225,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PasswordFinishRouteImport
parentRoute: typeof rootRouteImport
}
'/openid/callback': {
id: '/openid/callback'
path: '/openid/callback'
fullPath: '/openid/callback'
preLoaderRoute: typeof OpenidCallbackRouteImport
parentRoute: typeof rootRouteImport
}
}
}

Expand All @@ -222,6 +242,7 @@ const rootRouteChildren: RootRouteChildren = {
EnrollmentStartRoute: EnrollmentStartRoute,
PasswordResetRoute: PasswordResetRoute,
TestRoute: TestRoute,
OpenidCallbackRoute: OpenidCallbackRoute,
PasswordFinishRoute: PasswordFinishRoute,
PasswordSentRoute: PasswordSentRoute,
PasswordIndexRoute: PasswordIndexRoute,
Expand Down
59 changes: 52 additions & 7 deletions webnext/src/routes/client-setup.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,71 @@
import { createFileRoute, redirect } from '@tanstack/react-router';
import z from 'zod';
import { ConfigureClientPage } from '../pages/enrollment/ConfigureClient/ConfigureClientPage';
import { api } from '../shared/api/api';
import type { EnrollmentStartResponse } from '../shared/api/types';
import { isPresent } from '../shared/defguard-ui/utils/isPresent';
import { useEnrollmentStore } from '../shared/hooks/useEnrollmentStore';

const _fetchDesktop = async () => {
const _resp = await fetch('https://api.git.com/repos/defguard/client/releases/latest', {
method: 'GET',
});
};
const schema = z.object({
code: z.string().trim().optional(),
state: z.string().trim().optional(),
});

export const Route = createFileRoute('/client-setup')({
component: ConfigureClientPage,
beforeLoad: () => {
validateSearch: schema,
loaderDeps: ({ search }) => ({ search }),
beforeLoad: ({ search }) => {
// if openId flow just pass the search to the context
if (search && isPresent(search.code) && isPresent(search.state)) {
return {
openid: {
code: search.code,
state: search.state,
},
};
}
// if not openId then expect state to be in session
const state = useEnrollmentStore.getState();
if (state.token === undefined || state.enrollmentData === undefined) {
throw redirect({
to: '/enrollment-start',
replace: true,
});
}
return {
openid: undefined,
};
},
loader: () => {
loader: async ({ context: { openid } }) => {
if (openid) {
try {
const openIdResponse = await api.openId.enrollmentCallback.callbackFn({
data: {
code: openid.code,
state: openid.state,
type: 'enrollment',
},
});

const enrollResponse = await api.enrollment.start.callbackFn({
data: {
token: openIdResponse.data.token,
},
});

return {
token: openIdResponse.data.token,
enrollmentData: enrollResponse.data,
};
} catch (e) {
console.error(e);
throw redirect({
to: '/',
replace: true,
});
}
}
const state = useEnrollmentStore.getState();
return {
token: state.token as string,
Expand Down
12 changes: 3 additions & 9 deletions webnext/src/routes/enrollment-start.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import { createFileRoute, redirect } from '@tanstack/react-router';
import { createFileRoute } from '@tanstack/react-router';
import type { AxiosError } from 'axios';
import { EnrollmentStartPage } from '../pages/enrollment/EnrollmentStart/EnrollmentStartPage';
import { api } from '../shared/api/api';

export const Route = createFileRoute('/enrollment-start')({
component: EnrollmentStartPage,
loader: async () => {
// workaround cuz this endpoint throws 404 when openid is not configured
const resp = await api.openId.authInfo
.callbackFn({
data: {
type: 'enrollment',
},
})
.catch((e: AxiosError) => {
//FIXME: should redirect
if (e.status !== 500) {
throw redirect({
to: '/',
replace: true,
});
}
console.error(e);
});
//FIXME
return resp?.data;
},
});
24 changes: 24 additions & 0 deletions webnext/src/routes/openid/callback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createFileRoute, redirect } from '@tanstack/react-router';
import z from 'zod';

const schema = z.object({
state: z.string().trim().min(1),
code: z.string().trim().min(1),
});

// this route exists only for redirect, this is done to maintain compatibility with old UI and retain existing links
export const Route = createFileRoute('/openid/callback')({
component: RouteComponent,
validateSearch: schema,
loaderDeps: ({ search }) => ({ search }),
beforeLoad: ({ search }) => {
throw redirect({
to: '/client-setup',
search: search,
});
},
});

function RouteComponent() {
return null;
}
49 changes: 49 additions & 0 deletions webnext/src/shared/defguard-ui/components/FieldBox/FieldBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import './style.scss';
import clsx from 'clsx';
import { isPresent } from '../../utils/isPresent';
import { Icon } from '../Icon';
import { InteractionBox } from '../InteractionBox/InteractionBox';
import type { FieldBoxProps } from './types';

// generalized field box for components like Input, shouldn't be in layout on it's own
export const FieldBox = ({
children,
disabled,
error,
className,
boxRef,
interactionRef,
iconLeft,
iconRight,
size,
onInteractionClick,
...rest
}: FieldBoxProps) => {
const hasIconLeft = isPresent(iconLeft);
const hasIconRight = isPresent(iconRight);
return (
<div
className={clsx('field-box', className, `size-${size}`, {
'grid-default': !hasIconLeft && !hasIconRight,
'grid-left': hasIconLeft && !hasIconRight,
'grid-right': hasIconRight && !hasIconLeft,
'grid-both': hasIconLeft && hasIconRight,
disabled,
error,
})}
{...rest}
>
{hasIconLeft && <Icon icon={iconLeft} size={20} />}
{children}
{hasIconRight && (
<InteractionBox
disabled={disabled}
iconSize={20}
icon={iconRight}
onClick={onInteractionClick}
tabIndex={-1}
/>
)}
</div>
);
};
Loading