Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production deploy #2559

Merged
merged 7 commits into from
Dec 12, 2023
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
36 changes: 36 additions & 0 deletions api.planx.uk/modules/auth/middleware.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { isEqual } from "./middleware";

describe("isEqual() helper function", () => {
it("handles undefined secrets", () => {
const req = { headers: { "api-key": undefined } };
const result = isEqual(req.headers["api-key"], process.env.UNSET_SECRET!);
expect(result).toBe(false);
});

it("handles null values", () => {
const req = { headers: { "api-key": null } };
// @ts-expect-error "api-key" purposefully set to wrong type
const result = isEqual(req.headers["api-key"], null!);
expect(result).toBe(false);
});

it("handles undefined headers", () => {
const req = { headers: { "some-other-header": "test123" } };
// @ts-expect-error "api-key" purposefully not set
const result = isEqual(req.headers["api-key"]!, process.env.UNSET_SECRET!);
expect(result).toBe(false);
});

it("handles empty strings", () => {
const req = { headers: { "api-key": "" } };
expect(isEqual(req.headers["api-key"], "")).toBe(false);
});

it("matches equal values", () => {
expect(isEqual("square", "square")).toBe(true);
});

it("does not match different values", () => {
expect(isEqual("circle", "triangle")).toBe(false);
});
});
5 changes: 4 additions & 1 deletion api.planx.uk/modules/auth/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ export const userContext = new AsyncLocalStorage<{ user: Express.User }>();
/**
* Validate that a provided string (e.g. API key) matches the expected value
*/
const isEqual = (provided = "", expected: string): boolean => {
export const isEqual = (provided = "", expected: string): boolean => {
// Reject test against falsey values - could indicate unset secret
if (!expected) return false;

const hash = crypto.createHash("SHA512");
return crypto.timingSafeEqual(
hash.copy().update(provided).digest(),
Expand Down
5 changes: 5 additions & 0 deletions api.planx.uk/modules/pay/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ describe("sending a payment to GOV.UK Pay", () => {
reference: "12343543",
description: "New application",
return_url: "https://editor.planx.uk",
metadata: {
source: "PlanX",
flow: "apply-for-a-lawful-development-certificate",
inviteToPay: false,
},
})
.expect(200)
.then((res) => {
Expand Down
12 changes: 12 additions & 0 deletions api.planx.uk/modules/pay/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ interface GovPayCreatePayment {
reference: string;
description: string;
return_url: string;
metadata?: {
source: "PlanX";
flow: string;
inviteToPay: boolean;
};
}

export async function buildPaymentPayload(
Expand Down Expand Up @@ -120,6 +125,13 @@ export async function buildPaymentPayload(
reference: req.query.sessionId as string,
description: "New application (nominated payee)",
return_url: req.query.returnURL as string,
metadata: {
source: "PlanX",
flow:
new URL(req.query.returnURL as string).pathname.split("/")[0] ||
(req.query.returnURL as string),
inviteToPay: true,
},
};

req.body = createPaymentBody;
Expand Down
2 changes: 1 addition & 1 deletion editor.planx.uk/src/@planx/components/Checklist/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ const Options: React.FC<{ formik: FormikHookReturn }> = ({ formik }) => {
</IconButton>
</Box>
</Box>
<Box pl={4}>
<Box pl={{ md: 2 }}>
<ListManager
values={groupedOption.children}
onChange={(newOptions) => {
Expand Down
11 changes: 10 additions & 1 deletion editor.planx.uk/src/@planx/components/Pay/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ export interface GovUKCreatePaymentPayload {
};
};
language?: string;
metadata?: any;
metadata?: {
source: "PlanX";
flow: string;
inviteToPay: boolean;
};
}

export const toPence = (decimal: number) => Math.trunc(decimal * 100);
Expand All @@ -63,6 +67,11 @@ export const createPayload = (
reference,
description: "New application",
return_url: getReturnURL(reference),
metadata: {
source: "PlanX",
flow: useStore.getState().flowSlug,
inviteToPay: false,
},
});

/**
Expand Down
2 changes: 1 addition & 1 deletion editor.planx.uk/src/@planx/components/Question/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const OptionEditor: React.FC<{
},
});
}}
sx={{ width: "160px", maxWidth: "160px" }}
sx={{ width: { md: "160px" }, maxWidth: "160px" }}
/>
</InputRow>
<InputRow>
Expand Down
1 change: 0 additions & 1 deletion editor.planx.uk/src/ui/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ const StyledInputBase = styled(InputBase, {
...(format === "large" && {
backgroundColor: theme.palette.common.white,
height: 50,
fontSize: 25,
width: "100%",
fontWeight: FONT_WEIGHT_SEMI_BOLD,
}),
Expand Down
14 changes: 12 additions & 2 deletions editor.planx.uk/src/ui/ModalSectionContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,26 @@ const SectionContentGrid = styled(Grid)(({ theme }) => ({
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
flexWrap: "nowrap",
[theme.breakpoints.down("md")]: {
flexDirection: "column",
alignItems: "flex-start",
},
}));

const LeftGutter = styled(Grid)(({ theme }) => ({
flex: `0 0 ${theme.spacing(6)}`,
flex: `0 0 ${theme.spacing(3)}`,
textAlign: "center",
[theme.breakpoints.up("md")]: {
flex: `0 0 ${theme.spacing(6)}`,
},
}));

const SectionContent = styled(Grid)(({ theme }) => ({
flexGrow: 1,
paddingRight: theme.spacing(6),
width: "100%",
[theme.breakpoints.up("md")]: {
paddingRight: theme.spacing(6),
},
}));

const Title = styled(Typography)(({ theme }) => ({
Expand Down
1 change: 1 addition & 0 deletions editor.planx.uk/src/ui/RichTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const RichContentContainer = styled(Box)(({ theme }) => ({
display: "flex",
flexDirection: "column",
justifyContent: "center",
wordBreak: "break-word",
"& a": {
color: "currentColor",
},
Expand Down
6 changes: 5 additions & 1 deletion editor.planx.uk/src/ui/SelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ const classes = {

const Root = styled(Select)(({ theme }) => ({
width: "100%",
padding: theme.spacing(0, 1.5),
padding: 0,
height: 50,
backgroundColor: "#fff",
"& .MuiSelect-select": {
width: "100%",
padding: theme.spacing(1, 1.5),
},
[`&.${classes.rootSelect}`]: {
paddingRight: theme.spacing(6),
boxSizing: "border-box",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
DROP VIEW public.analytics_summary CASCADE;

CREATE OR REPLACE VIEW public.analytics_summary AS
select
a.id as analytics_id,
al.id as analytics_log_id,
f.slug as service_slug,
t.slug as team_slug,
a.type as analytics_type,
a.created_at as analytics_created_at,
user_agent,
referrer,
flow_direction,
metadata,
al.user_exit as is_user_exit,
node_type,
node_title,
has_clicked_help,
input_errors,
CAST(EXTRACT(EPOCH FROM (al.next_log_created_at - al.created_at)) as numeric (10, 1)) as time_spent_on_node_seconds
from analytics a
left join analytics_logs al on a.id = al.analytics_id
left join flows f on a.flow_id = f.id
left join teams t on t.id = f.team_id;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
CREATE OR REPLACE VIEW public.analytics_summary AS
select
a.id as analytics_id,
al.id as analytics_log_id,
f.slug as service_slug,
t.slug as team_slug,
a.type as analytics_type,
a.created_at as analytics_created_at,
user_agent,
referrer,
flow_direction,
metadata,
al.user_exit as is_user_exit,
node_type,
node_title,
has_clicked_help,
input_errors,
CAST(EXTRACT(EPOCH FROM (al.next_log_created_at - al.created_at)) as numeric (10, 1)) as time_spent_on_node_seconds,
a.ended_at as analytics_ended_at,
CAST(EXTRACT(EPOCH FROM (a.ended_at - a.created_at))/60 as numeric (10, 1)) as time_spent_on_analytics_session_minutes
from analytics a
left join analytics_logs al on a.id = al.analytics_id
left join flows f on a.flow_id = f.id
left join teams t on t.id = f.team_id;
2 changes: 2 additions & 0 deletions infrastructure/application/Pulumi.production.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ config:
application:cloudflare-zone-id: a9b9933f28e786ec4cfd4bb596f5a519
application:file-api-key:
secure: AAABAGyTfLujGho+V0tEhFXQRET5FjYK6txyaFTB3gY/VaKzq8yNlocJTAM5nt8mBhF6T+AeQD2GxW63
application:file-api-key-nexus:
secure: AAABAB2cv4GAf8RqN1hHbRbO68p8o4kLJYWsip9BoPdobrNtQB787M3s+gJnKKl9DfyXRHOXHGc=
application:google-client-id: 987324067365-vpsk3kgeq5n32ihjn760ihf8l7m5rhh8.apps.googleusercontent.com
application:google-client-secret:
secure: AAABAN5E+De3A3HtpLVaSNTDwk9Uz4r2d5g8SIRVbNOd2fj3eU+lGJXjVbEAnxezr14hwabbfwW2ptjcFzqkhG7OmQ==
Expand Down
Loading