Skip to content

Commit

Permalink
feat: add functionality to remove password
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderleegs committed Jun 26, 2023
1 parent f51c795 commit 478aca0
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 24 deletions.
3 changes: 2 additions & 1 deletion src/routes/v2/authenticatedSites/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@ class SettingsRouter {
const { error } = UpdateRepoPasswordRequestSchema.validate(req.body)
if (error) throw new BadRequestError(error.message)

const { encryptedPassword, iv } = body
const { encryptedPassword, iv, enablePassword } = body
const passwordRes = await this.settingsService.updatePassword(
userWithSiteSessionData,
{
encryptedPassword,
iv,
enablePassword,
}
)

Expand Down
11 changes: 6 additions & 5 deletions src/services/configServices/SettingsService.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,24 +154,24 @@ class SettingsService {
}
}

async updatePassword(sessionData, { encryptedPassword, iv }) {
async updatePassword(sessionData, { encryptedPassword, iv, enablePassword }) {
const { siteName } = sessionData
const siteInfo = await this.sitesService.getBySiteName(siteName)
if (siteInfo.isErr()) {
return siteInfo
}
const { id, isPrivate } = siteInfo.value
if (!isPrivate) {
if (isPrivate !== enablePassword) {
// For previously public repos, also need to set github repo to private
const privatiseRepoRes = await this.gitHubService.changeRepoPrivacy(
sessionData,
true
enablePassword
)
if (privatiseRepoRes.isErr()) return privatiseRepoRes
try {
await this.sitesService.update({
id,
isPrivate: true,
isPrivate: enablePassword,
})
} catch (err) {
return errAsync(err)
Expand All @@ -180,7 +180,8 @@ class SettingsService {
return this.deploymentsService.updateAmplifyPassword(
siteName,
encryptedPassword,
iv
iv,
enablePassword
)
}

Expand Down
219 changes: 219 additions & 0 deletions src/services/configServices/__tests__/SettingsService.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
const { okAsync, errAsync } = require("neverthrow")

const { configContent, configSha } = require("@fixtures/config")
const { footerContent, footerSha } = require("@fixtures/footer")
const { homepageContent, homepageSha } = require("@fixtures/homepage")
const { navigationContent, navigationSha } = require("@fixtures/navigation")
const { mockUserWithSiteSessionData } = require("@fixtures/sessionData")
const {
MOCK_SITE_DBENTRY_ONE,
MOCK_SITE_DBENTRY_TWO,
MOCK_DEPLOYMENT_DBENTRY_TWO,
} = require("@fixtures/sites")
const { NotFoundError } = require("@root/errors/NotFoundError")

const { SettingsService } = require("../SettingsService")

Expand Down Expand Up @@ -44,11 +52,28 @@ describe("Settings Service", () => {
update: jest.fn(),
}

const mockSitesService = {
getBySiteName: jest.fn(),
update: jest.fn(),
}

const mockDeploymentsService = {
getDeploymentInfoFromSiteId: jest.fn(),
updateAmplifyPassword: jest.fn(),
}

const mockGitHubService = {
changeRepoPrivacy: jest.fn(),
}

const service = new SettingsService({
configYmlService: mockConfigYmlService,
homepagePageService: mockHomepagePageService,
footerYmlService: mockFooterYmlService,
navYmlService: mockNavYmlService,
sitesService: mockSitesService,
deploymentsService: mockDeploymentsService,
gitHubService: mockGitHubService,
})

afterEach(() => {
Expand Down Expand Up @@ -91,6 +116,68 @@ describe("Settings Service", () => {
})
})

describe("getEncryptedPassword", () => {
it("retrieves password data successfully for private amplify repos", async () => {
// Arrange
mockSitesService.getBySiteName.mockResolvedValue(
okAsync(MOCK_SITE_DBENTRY_TWO)
)
mockDeploymentsService.getDeploymentInfoFromSiteId.mockResolvedValue(
okAsync(MOCK_DEPLOYMENT_DBENTRY_TWO)
)

// Act
const resp = await service.getEncryptedPassword(
mockUserWithSiteSessionData
)

// Assert
expect(resp.value).toMatchObject({
encryptedPassword: MOCK_DEPLOYMENT_DBENTRY_TWO.encryptedPassword,
iv: MOCK_DEPLOYMENT_DBENTRY_TWO.encryptionIv,
isAmplifySite: true,
})
})

it("returns appropriate response for non-private amplify repos", async () => {
// Arrange
mockSitesService.getBySiteName.mockResolvedValue(
okAsync(MOCK_SITE_DBENTRY_ONE)
)

// Act
const resp = await service.getEncryptedPassword(
mockUserWithSiteSessionData
)

// Assert
expect(resp.value).toMatchObject({
encryptedPassword: "",
iv: "",
isAmplifySite: true,
})
})

it("returns appropriate response for netlify repos", async () => {
// Arrange
mockSitesService.getBySiteName.mockResolvedValue(
errAsync(new NotFoundError())
)

// Act
const resp = await service.getEncryptedPassword(
mockUserWithSiteSessionData
)

// Assert
expect(resp.value).toMatchObject({
encryptedPassword: "",
iv: "",
isAmplifySite: false,
})
})
})

describe("Update settings files", () => {
mockConfigYmlService.read.mockResolvedValue(config)
mockFooterYmlService.read.mockResolvedValue(footer)
Expand Down Expand Up @@ -373,4 +460,136 @@ describe("Settings Service", () => {
)
})
})

describe.only("updatePassword", () => {
const encryptedPassword = "newPass"
const iv = "iv"

it("updates password for private amplify repos", async () => {
// Arrange
const enablePassword = true
mockSitesService.getBySiteName.mockResolvedValue(
okAsync(MOCK_SITE_DBENTRY_TWO)
)
mockDeploymentsService.updateAmplifyPassword.mockResolvedValue(
okAsync("")
)

// Act
await service.updatePassword(mockUserWithSiteSessionData, {
encryptedPassword,
iv,
enablePassword,
})

// Assert
expect(mockGitHubService.changeRepoPrivacy).not.toHaveBeenCalled()
expect(mockSitesService.update).not.toHaveBeenCalled()
expect(
mockDeploymentsService.updateAmplifyPassword
).toHaveBeenLastCalledWith(
mockUserWithSiteSessionData.siteName,
encryptedPassword,
iv,
enablePassword
)
})

it("updates password for previously public amplify repos", async () => {
// Arrange
const enablePassword = true
mockSitesService.getBySiteName.mockResolvedValue(
okAsync(MOCK_SITE_DBENTRY_ONE)
)
mockGitHubService.changeRepoPrivacy.mockResolvedValueOnce(okAsync(""))
mockSitesService.update.mockResolvedValue("")
mockDeploymentsService.updateAmplifyPassword.mockResolvedValue(
okAsync("")
)

// Act
await service.updatePassword(mockUserWithSiteSessionData, {
encryptedPassword,
iv,
enablePassword,
})

// Assert
expect(mockGitHubService.changeRepoPrivacy).toHaveBeenLastCalledWith(
mockUserWithSiteSessionData,
enablePassword
)
expect(mockSitesService.update).toHaveBeenLastCalledWith({
id: MOCK_SITE_DBENTRY_ONE.id,
isPrivate: enablePassword,
})
expect(
mockDeploymentsService.updateAmplifyPassword
).toHaveBeenLastCalledWith(
mockUserWithSiteSessionData.siteName,
encryptedPassword,
iv,
enablePassword
)
})

it("removes password for previously private amplify repos", async () => {
// Arrange
const enablePassword = false
mockSitesService.getBySiteName.mockResolvedValue(
okAsync(MOCK_SITE_DBENTRY_TWO)
)
mockGitHubService.changeRepoPrivacy.mockResolvedValueOnce(okAsync(""))
mockSitesService.update.mockResolvedValue("")
mockDeploymentsService.updateAmplifyPassword.mockResolvedValue(
okAsync("")
)

// Act
await service.updatePassword(mockUserWithSiteSessionData, {
encryptedPassword,
iv,
enablePassword,
})

// Assert
expect(mockGitHubService.changeRepoPrivacy).toHaveBeenLastCalledWith(
mockUserWithSiteSessionData,
enablePassword
)
expect(mockSitesService.update).toHaveBeenLastCalledWith({
id: MOCK_SITE_DBENTRY_TWO.id,
isPrivate: enablePassword,
})
expect(
mockDeploymentsService.updateAmplifyPassword
).toHaveBeenLastCalledWith(
mockUserWithSiteSessionData.siteName,
encryptedPassword,
iv,
enablePassword
)
})

it("fails if attempting to change password on a netlify repo", async () => {
// Arrange
const thrownErr = new NotFoundError()
mockSitesService.getBySiteName.mockResolvedValue(errAsync(thrownErr))

// Act
const resp = await service.updatePassword(mockUserWithSiteSessionData, {
encryptedPassword,
iv,
enablePassword: true,
})

// Assert
expect(resp.error).toBe(thrownErr)
expect(mockGitHubService.changeRepoPrivacy).not.toHaveBeenCalled()
expect(mockSitesService.update).not.toHaveBeenCalled()
expect(
mockDeploymentsService.updateAmplifyPassword
).not.toHaveBeenCalled()
})
})
})
24 changes: 18 additions & 6 deletions src/services/identity/DeploymentClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,24 @@ class DeploymentClient {
generateUpdatePasswordInput = (
appId: string,
password: string
): UpdateBranchCommandInput => ({
appId,
branchName: "staging",
enableBasicAuth: true,
basicAuthCredentials: Buffer.from(`user:${password}`).toString("base64"),
})
): UpdateBranchCommandInput => {
if (password) {
return {
appId,
branchName: "staging",
enableBasicAuth: true,
basicAuthCredentials: Buffer.from(`user:${password}`).toString(
"base64"
),
}
}
return {
appId,
branchName: "staging",
enableBasicAuth: false,
basicAuthCredentials: "",
}
}
}

export default DeploymentClient
Loading

0 comments on commit 478aca0

Please sign in to comment.