[go: nahoru, domu]

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

passkey config admin changes #2326

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
629f8ac
passkey config admin changes
pragatimodi Oct 4, 2023
a2c2431
Bug Fix for issue #2320 (#2321)
rishabhAjay Oct 3, 2023
62b0003
fixed unit test errors
dependabot[bot] Oct 4, 2023
f0b0ea6
lint fixes + integration
dependabot[bot] Oct 12, 2023
ac9a82f
remove integration tests
pragatimodi Oct 18, 2023
b40b1ab
adding comments
pragatimodi Oct 18, 2023
b35cb33
undo package json changes
pragatimodi Oct 18, 2023
8bd4d39
Merge branch 'master' into passkeys
pragatimodi Oct 18, 2023
5c16959
passkey config admin changes
pragatimodi Oct 4, 2023
218e7d3
fixed unit test errors
dependabot[bot] Oct 4, 2023
0977e7a
lint fixes + integration
dependabot[bot] Oct 12, 2023
dfe7f4a
remove integration tests
pragatimodi Oct 18, 2023
1bb1526
undo package json changes
pragatimodi Oct 18, 2023
abfb295
adding comments
pragatimodi Oct 18, 2023
045d959
Merge branch 'passkeys' of https://github.com/firebase/firebase-admin…
pragatimodi Oct 18, 2023
fff81ce
undo package json changes
pragatimodi Oct 18, 2023
9d69dd8
undo package json changes
pragatimodi Oct 18, 2023
7127be9
Merge branch 'passkeys' of https://github.com/firebase/firebase-admin…
pragatimodi Oct 18, 2023
1ab9273
undo duplicate npm changes
pragatimodi Oct 18, 2023
c294ff4
Apply suggestions from code review
pragatimodi Oct 19, 2023
6492438
update toJSON for string values
pragatimodi Apr 2, 2024
f9d35c3
Merge branch 'master' into passkeys
pragatimodi Apr 3, 2024
041bf17
user record changes for getAccountInfo() (#2341)
pragatimodi Apr 3, 2024
0389dc1
correct endpoint
pragatimodi Apr 3, 2024
5364938
fix tenant endpoint handling
pragatimodi Apr 3, 2024
8d3384b
fix lint
pragatimodi Apr 3, 2024
cec0cbe
add api:extractor changes
pragatimodi Apr 3, 2024
2c70e61
remove uncommented code
pragatimodi Jun 26, 2024
64203c3
Merge branch 'master' into passkeys
pragatimodi Jun 27, 2024
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
Prev Previous commit
Next Next commit
lint fixes + integration
  • Loading branch information
dependabot[bot] authored and pragatimodi committed Oct 18, 2023
commit f0b0ea6ed2c0405d1cef109dd0e1c115d5778302
40 changes: 20 additions & 20 deletions package-lock.json

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

14 changes: 9 additions & 5 deletions src/auth/auth-api-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
SAMLUpdateAuthProviderRequest
} from './auth-config';
import { ProjectConfig, ProjectConfigServerResponse, UpdateProjectConfigRequest } from './project-config';
import {PasskeyConfig, PasskeyConfigServerResponse, PasskeyConfigRequest} from './passkey-config';
import { PasskeyConfig, PasskeyConfigServerResponse, PasskeyConfigRequest } from './passkey-config';

/** Firebase Auth request header. */
const FIREBASE_AUTH_HEADER = {
Expand Down Expand Up @@ -2108,7 +2108,8 @@ const UPDATE_PASSKEY_CONFIG = new ApiSettings('/passkeyConfig?updateMask={update
});

/** Instantiates the getPasskeyConfig endpoint settings. */
const UPDATE_TENANT_PASSKEY_CONFIG = new ApiSettings('/tenant/{tenantId}/passkeyConfig?updateMask={updateMask}', 'PATCH')
const UPDATE_TENANT_PASSKEY_CONFIG = new ApiSettings(
'/tenant/{tenantId}/passkeyConfig?updateMask={updateMask}', 'PATCH')
.setResponseValidator((response: any) => {
// Response should always contain at least the config name.
if (!validator.isNonEmptyString(response.name)) {
Expand Down Expand Up @@ -2296,18 +2297,21 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
}

public getPasskeyConfig(tenantId?: string): Promise<PasskeyConfigServerResponse> {
return this.invokeRequestHandler(this.authResourceUrlBuilder, tenantId? GET_TENANT_PASSKEY_CONFIG: GET_PASSKEY_CONFIG, {}, {})
return this.invokeRequestHandler(this.authResourceUrlBuilder,
tenantId? GET_TENANT_PASSKEY_CONFIG: GET_PASSKEY_CONFIG, {}, {})
.then((response: any) => {
return response as PasskeyConfigServerResponse;
});
}

public updatePasskeyConfig(isCreateRequest: boolean, tenantId?: string, options?: PasskeyConfigRequest, rpId?: string): Promise<PasskeyConfigServerResponse> {
public updatePasskeyConfig(isCreateRequest: boolean, tenantId?: string,
options?: PasskeyConfigRequest, rpId?: string): Promise<PasskeyConfigServerResponse> {
try {
const request = PasskeyConfig.buildServerRequest(isCreateRequest, options, rpId);
const updateMask = utils.generateUpdateMask(request);
return this.invokeRequestHandler(
this.authResourceUrlBuilder, tenantId? UPDATE_TENANT_PASSKEY_CONFIG: UPDATE_PASSKEY_CONFIG, request, { updateMask: updateMask.join(',') })
this.authResourceUrlBuilder, tenantId? UPDATE_TENANT_PASSKEY_CONFIG: UPDATE_PASSKEY_CONFIG,
request, { updateMask: updateMask.join(',') })
.then((response: any) => {
return response as PasskeyConfigServerResponse;
});
Expand Down
10 changes: 8 additions & 2 deletions src/auth/passkey-config-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ import { App } from '../app';
import {
AuthRequestHandler,
} from './auth-api-request';
import { PasskeyConfig, PasskeyConfigClientRequest, PasskeyConfigRequest, PasskeyConfigServerResponse } from './passkey-config';
import {
PasskeyConfig,
PasskeyConfigClientRequest,
PasskeyConfigRequest,
PasskeyConfigServerResponse
} from './passkey-config';


export class PasskeyConfigManager {
Expand All @@ -34,7 +39,8 @@ export class PasskeyConfigManager {
});
}

public createPasskeyConfig(rpId: string, passkeyConfigRequest: PasskeyConfigRequest, tenantId?: string): Promise<PasskeyConfig> {
public createPasskeyConfig(rpId: string, passkeyConfigRequest: PasskeyConfigRequest,
tenantId?: string): Promise<PasskeyConfig> {
return this.authRequestHandler.updatePasskeyConfig(true, tenantId, passkeyConfigRequest, rpId)
.then((response: PasskeyConfigClientRequest) => {
return new PasskeyConfig(response);
Expand Down
101 changes: 51 additions & 50 deletions src/auth/passkey-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
import * as validator from '../utils/validator';
import { AuthClientErrorCode, FirebaseAuthError } from '../utils/error';
import {deepCopy} from '../utils/deep-copy';
import { deepCopy } from '../utils/deep-copy';

export interface PasskeyConfigRequest {
expectedOrigins?: string[];
Expand All @@ -38,94 +38,95 @@ export class PasskeyConfig {
public readonly rpId?: string;
public readonly expectedOrigins?: string[];

private static validate(isCreateRequest: boolean, passkeyConfigRequest?: PasskeyConfigRequest, rpId?: string) {
if(isCreateRequest && !validator.isNonEmptyString(rpId)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'rpId' must be a valid non-empty string'`,
);
private static validate(isCreateRequest: boolean, passkeyConfigRequest?: PasskeyConfigRequest, rpId?: string): void {
if (isCreateRequest && !validator.isNonEmptyString(rpId)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'\'rpId\' must be a valid non-empty string\'',
);
}
if(!isCreateRequest && typeof rpId !== 'undefined') {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'rpId' cannot be changed once created.'`,
);
if (!isCreateRequest && typeof rpId !== 'undefined') {
pragatimodi marked this conversation as resolved.
Show resolved Hide resolved
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'\'rpId\' cannot be changed once created.\'',
);
}
if(!validator.isNonNullObject(passkeyConfigRequest)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'passkeyConfigRequest' must be a valid non-empty object.'`,
);
if (!validator.isNonNullObject(passkeyConfigRequest)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'\'passkeyConfigRequest\' must be a valid non-empty object.\'',
);
}
const validKeys = {
expectedOrigins: true,
expectedOrigins: true,
};
// Check for unsupported top level attributes.
for (const key in passkeyConfigRequest) {
if (!(key in validKeys)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'${key}' is not a valid PasskeyConfigRequest parameter.`,
);
}
}
if(!validator.isNonEmptyArray(passkeyConfigRequest.expectedOrigins)) {
if (!(key in validKeys)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'passkeyConfigRequest.expectedOrigins' must be a valid non-empty array of strings.'`,
);
AuthClientErrorCode.INVALID_ARGUMENT,
`'${key}' is not a valid PasskeyConfigRequest parameter.`,
);
}
}
if (!validator.isNonEmptyArray(passkeyConfigRequest.expectedOrigins)) {
Xiaoshouzi-gh marked this conversation as resolved.
Show resolved Hide resolved
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'\'passkeyConfigRequest.expectedOrigins\' must be a valid non-empty array of strings.\'',
);
}
for (const origin of passkeyConfigRequest.expectedOrigins) {
if (!validator.isNonEmptyString(origin)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'passkeyConfigRequest.expectedOrigins' must be a valid non-empty array of strings.'`,
'\'passkeyConfigRequest.expectedOrigins\' must be a valid non-empty array of strings.\'',
);
}
}
};
}

public static buildServerRequest(isCreateRequest: boolean, passkeyConfigRequest?: PasskeyConfigRequest, rpId?: string): PasskeyConfigClientRequest {
public static buildServerRequest(isCreateRequest: boolean, passkeyConfigRequest?: PasskeyConfigRequest,
rpId?: string): PasskeyConfigClientRequest {
PasskeyConfig.validate(isCreateRequest, passkeyConfigRequest, rpId);
let request: PasskeyConfigClientRequest = {};
if(isCreateRequest && typeof rpId !== 'undefined') {
request.rpId = rpId;
const request: PasskeyConfigClientRequest = {};
if (isCreateRequest && typeof rpId !== 'undefined') {
request.rpId = rpId;
}
if(typeof passkeyConfigRequest?.expectedOrigins !== 'undefined') {
request.expectedOrigins = passkeyConfigRequest.expectedOrigins;
if (typeof passkeyConfigRequest?.expectedOrigins !== 'undefined') {
request.expectedOrigins = passkeyConfigRequest.expectedOrigins;
}
return request;
};
}

constructor(response: PasskeyConfigServerResponse) {
if(typeof response.name !== 'undefined') {
this.name = response.name;
if (typeof response.name !== 'undefined') {
this.name = response.name;
}
if(typeof response.rpId !== 'undefined') {
this.rpId = response.rpId;
};
if(typeof response.expectedOrigins !== 'undefined') {
this.expectedOrigins = response.expectedOrigins;
if (typeof response.rpId !== 'undefined') {
this.rpId = response.rpId;
}
};
if (typeof response.expectedOrigins !== 'undefined') {
this.expectedOrigins = response.expectedOrigins;
}
}

public toJSON(): object {
const json = {
name: deepCopy(this.name),
pragatimodi marked this conversation as resolved.
Show resolved Hide resolved
rpId: deepCopy(this.rpId),
expectedOrigins: deepCopy(this.expectedOrigins),
};
if(typeof json.name === 'undefined') {
if (typeof json.name === 'undefined') {
delete json.name;
}
if(typeof json.rpId === 'undefined') {
if (typeof json.rpId === 'undefined') {
delete json.rpId;
}
if(typeof json.expectedOrigins === 'undefined') {
if (typeof json.expectedOrigins === 'undefined') {
delete json.expectedOrigins;
}
return json;
}

};
}

45 changes: 22 additions & 23 deletions test/integration/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2198,44 +2198,43 @@ describe('admin.auth', () => {
});

describe('Passkey config management operations', () => {
// Define expected passkey configuration
const expectedPasskeyConfig = {
name: `projects/{$projectId}/passkeyConfig`,
rpId: `{$projectId}.firebaseapp.com`,
expectedOrigins: ['app1', 'example.com'],
};

// Before each test, reset the passkey config to the initial state
beforeEach(async () => {
const resetRequest = { expectedOrigins: expectedPasskeyConfig.expectedOrigins };
await getAuth().passkeyConfigManager().updatePasskeyConfig(resetRequest);
// const resetRequest = { expectedOrigins: expectedPasskeyConfig.expectedOrigins };
// await getAuth().passkeyConfigManager().updatePasskeyConfig(resetRequest);
});

it('createPasskeyConfig() should create passkey config with expected passkeyConfig', async () => {
const rpId = `{$projectId}.firebaseapp.com`;
const rpId = projectId + '.firebaseapp.com';
const createRequest = { expectedOrigins: ['app1', 'example.com'] };

const createdPasskeyConfig = await getAuth().passkeyConfigManager().createPasskeyConfig(rpId, createRequest);
const passkeyConfigObj = createdPasskeyConfig.toJSON();

expect(passkeyConfigObj).to.deep.equal(expectedPasskeyConfig);
expect(createdPasskeyConfig.name).to.deep.equal('projects/' + projectId + '/passkeyConfig');
expect(createdPasskeyConfig.rpId).to.deep.equal(projectId + '.firebaseapp.com');
expect(createdPasskeyConfig.expectedOrigins).to.deep.equal(['app1', 'example.com']);
});

// TODO: uncomment when the GET endpoint is released in prod
// it('getPasskeyConfig() should resolve with expected passkeyConfig', async () => {
// const actualPasskeyConfig = await getAuth().passkeyConfigManager().getPasskeyConfig();

it('getPasskeyConfig() should resolve with expected passkeyConfig', async () => {
const actualPasskeyConfig = await getAuth().passkeyConfigManager().getPasskeyConfig();
const actualPasskeyConfigObj = actualPasskeyConfig.toJSON();

expect(actualPasskeyConfigObj).to.deep.equal(expectedPasskeyConfig);
});
// expect(actualPasskeyConfig.name).to.deep.equal('projects/' + projectId + '/passkeyConfig');
// expect(actualPasskeyConfig.rpId).to.deep.equal(projectId + '.firebaseapp.com');
// expect(actualPasskeyConfig.expectedOrigins).to.deep.equal(['app1', 'example.com']);
// });

it('updatePasskeyConfig() should resolve with updated expectedOrigins', async () => {
const updateRequest = { expectedOrigins: ['app1', 'example.com', 'app2'] };
const expectedUpdatedPasskeyConfig = { ...expectedPasskeyConfig, expectedOrigins: updateRequest.expectedOrigins };
const updateRequest = {
expectedOrigins: ['app1', 'example.com', 'app2']
};

const updatedPasskeyConfig = await getAuth().passkeyConfigManager().updatePasskeyConfig(updateRequest);
const passkeyConfigObj = updatedPasskeyConfig.toJSON();

expect(passkeyConfigObj).to.deep.equal(expectedUpdatedPasskeyConfig);

expect(updatedPasskeyConfig.name).to.deep.equal('projects/' + projectId + '/passkeyConfig');
// TODO: backend validation needs to fixed in order for this statement to succeed.
// expect(updatedPasskeyConfig.rpId).to.deep.equal(projectId + '.firebaseapp.com');
expect(updatedPasskeyConfig.expectedOrigins).to.deep.equal(['app1', 'example.com', 'app2']);
});
});

Expand Down
Loading