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

Disallow editing of user properties that come from Cognito (#15033) #15034

Merged
merged 1 commit into from
Jan 21, 2025
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
33 changes: 30 additions & 3 deletions services/app-api/handlers/users/post/updateUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ export const main = handler(async (event, context) => {
await authorizeAdmin(event);
}

assertPayloadIsValid(data);

const params = {
TableName:
process.env.AUTH_USER_TABLE_NAME ?? process.env.AuthUserTableName,
Key: {
userId: currentUser["Items"][0].userId,
},
UpdateExpression:
"SET username = :username, #r = :role, states = :states, lastLogin = :lastLogin, usernameSub = :usernameSub",
"SET #r = :role, states = :states, lastLogin = :lastLogin",
ExpressionAttributeValues: {
":username": data.username,
":role": data.role,
":states": data.states ?? "",
":lastLogin": new Date().toISOString(),
":usernameSub": data.usernameSub ?? null,
},
ExpressionAttributeNames: {
"#r": "role",
Expand All @@ -51,3 +51,30 @@ function modifyingAnythingButAnEmptyStateList(incomingUser, existingUser) {
if (existingUser.states.length > 0) return true;
return false;
}

function assertPayloadIsValid (data) {
if (!data) {
throw new Error("User update payload is missing");
}

if (typeof data.role !== "string" || !data.role) {
throw new Error("Invalid user role - must be a nonempty string");
}
if (!["admin", "business", "state"].includes(data.role)) {
throw new Error("Invalid user role - must be an existing role");
}

if (data.states && data.states !== "null") {
if (!Array.isArray(data.states)) {
throw new Error("Invalid user states - must be an array");
}
for (let state of data.states) {
if (typeof state !== "string") {
throw new Error("Invalid user states - must be strings");
}
if (!/^[A-Z]{2}$/.test(state)) {
throw new Error("Invalid user states - must be 2-letter abbreviations");
}
}
}
}
1 change: 1 addition & 0 deletions services/ui-src/src/components/EditUser/EditUser.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ const EditUser = ({ stateList }) => {
value={user.username}
type="text"
onChange={e => updateLocalUser(e, "username")}
disabled={true}
name="username"
className="form-input"
/>
Expand Down
9 changes: 5 additions & 4 deletions services/ui-src/src/components/EditUser/EditUser.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,17 @@ describe("Test EditUser.js", () => {
renderComponent(mockUser);
await waitFor(() => expect(getUserById).toHaveBeenCalled());

const table = screen.getByTestId("table");
const usernameInput = table.querySelector(".userName input");
userEvent.type(usernameInput, "TY");
const roleDropdown = screen.getByPlaceholderText("Select a Role");
userEvent.click(roleDropdown);
const adminOption = screen.getByText("Admin User");
userEvent.click(adminOption);

const saveButton = screen.getByText("Update User", { selector: "button" });
userEvent.click(saveButton);

expect(updateUser).toHaveBeenCalledWith(
expect.objectContaining({
username: "QWERTY"
role: "admin",
})
);
});
Expand Down
Loading