Skip to content

Recaptcha Admin SDK related changes. #1603

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

Closed
wants to merge 5 commits into from
Closed
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
49 changes: 49 additions & 0 deletions etc/firebase-admin.auth.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface ActionCodeSettings {
export class Auth extends BaseAuth {
// Warning: (ae-forgotten-export) The symbol "App" needs to be exported by the entry point index.d.ts
get app(): App;
projectConfigManager(): ProjectConfigManager;
tenantManager(): TenantManager;
}

Expand Down Expand Up @@ -256,6 +257,18 @@ export class PhoneMultiFactorInfo extends MultiFactorInfo {
toJSON(): object;
}

// @public
export class ProjectConfig {
get recaptchaConfig(): RecaptchaConfig | undefined;
toJSON(): object;
}

// @public
export class ProjectConfigManager {
getProjectConfig(): Promise<ProjectConfig>;
updateProjectConfig(projectConfigOptions: UpdateProjectConfigRequest): Promise<ProjectConfig>;
}

// @public
export interface ProviderIdentifier {
// (undocumented)
Expand All @@ -264,6 +277,35 @@ export interface ProviderIdentifier {
providerUid: string;
}

// @public
export type RecaptchaAction = 'BLOCK';

// @public
export interface RecaptchaConfig {
emailPasswordEnforcementState?: RecaptchaProviderEnforcementState;
managedRules?: RecaptchaManagedRule[];
recaptchaKeys?: RecaptchaKey[];
useAccountDefender?: boolean;
}

// @public
export interface RecaptchaKey {
key: string;
type?: RecaptchaKeyClientType;
}

// @public
export type RecaptchaKeyClientType = 'WEB';

// @public
export interface RecaptchaManagedRule {
action?: RecaptchaAction;
endScore: number;
}

// @public
export type RecaptchaProviderEnforcementState = 'OFF' | 'AUDIT' | 'ENFORCE';

// @public
export interface SAMLAuthProviderConfig extends BaseAuthProviderConfig {
callbackURL?: string;
Expand Down Expand Up @@ -296,6 +338,7 @@ export class Tenant {
readonly displayName?: string;
get emailSignInConfig(): EmailSignInProviderConfig | undefined;
get multiFactorConfig(): MultiFactorConfig | undefined;
get recaptchaConfig(): RecaptchaConfig | undefined;
readonly tenantId: string;
readonly testPhoneNumbers?: {
[phoneNumber: string]: string;
Expand Down Expand Up @@ -338,6 +381,11 @@ export interface UpdatePhoneMultiFactorInfoRequest extends BaseUpdateMultiFactor
phoneNumber: string;
}

// @public
export interface UpdateProjectConfigRequest {
recaptchaConfig?: RecaptchaConfig;
}

// @public
export interface UpdateRequest {
disabled?: boolean;
Expand All @@ -358,6 +406,7 @@ export interface UpdateTenantRequest {
displayName?: string;
emailSignInConfig?: EmailSignInProviderConfig;
multiFactorConfig?: MultiFactorConfig;
recaptchaConfig?: RecaptchaConfig;
testPhoneNumbers?: {
[phoneNumber: string]: string;
} | null;
Expand Down
72 changes: 62 additions & 10 deletions src/auth/auth-api-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
OIDCAuthProviderConfig, SAMLAuthProviderConfig, OIDCUpdateAuthProviderRequest,
SAMLUpdateAuthProviderRequest
} from './auth-config';
import { ProjectConfig, ProjectConfigServerResponse, UpdateProjectConfigRequest } from './project-config';

/** Firebase Auth request header. */
const FIREBASE_AUTH_HEADER = {
Expand Down Expand Up @@ -102,7 +103,6 @@ const FIREBASE_AUTH_TENANT_URL_FORMAT = FIREBASE_AUTH_BASE_URL_FORMAT.replace(
const FIREBASE_AUTH_EMULATOR_TENANT_URL_FORMAT = FIREBASE_AUTH_EMULATOR_BASE_URL_FORMAT.replace(
'projects/{projectId}', 'projects/{projectId}/tenants/{tenantId}');


/** Maximum allowed number of tenants to download at one time. */
const MAX_LIST_TENANT_PAGE_SIZE = 1000;

Expand Down Expand Up @@ -1961,6 +1961,29 @@ export abstract class AbstractAuthRequestHandler {
}
}

/** Instantiates the getConfig endpoint settings. */
const GET_PROJECT_CONFIG = new ApiSettings('/config', 'GET')
.setResponseValidator((response: any) => {
// Response should always contain at least the config name.
if (!validator.isNonEmptyString(response.name)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INTERNAL_ERROR,
'INTERNAL ASSERT FAILED: Unable to get project config',
);
}
});

/** Instantiates the updateConfig endpoint settings. */
const UPDATE_PROJECT_CONFIG = new ApiSettings('/config?updateMask={updateMask}', 'PATCH')
.setResponseValidator((response: any) => {
// Response should always contain at least the config name.
if (!validator.isNonEmptyString(response.name)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INTERNAL_ERROR,
'INTERNAL ASSERT FAILED: Unable to update project config',
);
}
});

/** Instantiates the getTenant endpoint settings. */
const GET_TENANT = new ApiSettings('/tenants/{tenantId}', 'GET')
Expand Down Expand Up @@ -2029,13 +2052,13 @@ const CREATE_TENANT = new ApiSettings('/tenants', 'POST')


/**
* Utility for sending requests to Auth server that are Auth instance related. This includes user and
* tenant management related APIs. This extends the BaseFirebaseAuthRequestHandler class and defines
* Utility for sending requests to Auth server that are Auth instance related. This includes user, tenant,
* and project config management related APIs. This extends the BaseFirebaseAuthRequestHandler class and defines
* additional tenant management related APIs.
*/
export class AuthRequestHandler extends AbstractAuthRequestHandler {

protected readonly tenantMgmtResourceBuilder: AuthResourceUrlBuilder;
protected readonly authResourceUrlBuilder: AuthResourceUrlBuilder;

/**
* The FirebaseAuthRequestHandler constructor used to initialize an instance using a FirebaseApp.
Expand All @@ -2045,7 +2068,7 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
*/
constructor(app: App) {
super(app);
this.tenantMgmtResourceBuilder = new AuthResourceUrlBuilder(app, 'v2');
this.authResourceUrlBuilder = new AuthResourceUrlBuilder(app, 'v2');
}

/**
Expand All @@ -2062,6 +2085,35 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
return new AuthResourceUrlBuilder(this.app, 'v2');
}

/**
* Get the current project's config
* @returns A promise that resolves with the project config information.
*/
public getProjectConfig(): Promise<ProjectConfigServerResponse> {
return this.invokeRequestHandler(this.authResourceUrlBuilder, GET_PROJECT_CONFIG, {}, {})
.then((response: any) => {
return response as ProjectConfigServerResponse;
});
}

/**
* Update the current project's config.
* @returns A promise that resolves with the project config information.
*/
public updateProjectConfig(recaptchaOptions: UpdateProjectConfigRequest): Promise<ProjectConfigServerResponse> {
try {
const request = ProjectConfig.buildServerRequest(recaptchaOptions);
const updateMask = utils.generateUpdateMask(request);
return this.invokeRequestHandler(
this.authResourceUrlBuilder, UPDATE_PROJECT_CONFIG, request, { updateMask: updateMask.join(',') })
.then((response: any) => {
return response as ProjectConfigServerResponse;
});
} catch (e) {
return Promise.reject(e);
}
}

/**
* Looks up a tenant by tenant ID.
*
Expand All @@ -2072,7 +2124,7 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
if (!validator.isNonEmptyString(tenantId)) {
return Promise.reject(new FirebaseAuthError(AuthClientErrorCode.INVALID_TENANT_ID));
}
return this.invokeRequestHandler(this.tenantMgmtResourceBuilder, GET_TENANT, {}, { tenantId })
return this.invokeRequestHandler(this.authResourceUrlBuilder, GET_TENANT, {}, { tenantId })
.then((response: any) => {
return response as TenantServerResponse;
});
Expand Down Expand Up @@ -2102,7 +2154,7 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
if (typeof request.pageToken === 'undefined') {
delete request.pageToken;
}
return this.invokeRequestHandler(this.tenantMgmtResourceBuilder, LIST_TENANTS, request)
return this.invokeRequestHandler(this.authResourceUrlBuilder, LIST_TENANTS, request)
.then((response: any) => {
if (!response.tenants) {
response.tenants = [];
Expand All @@ -2122,7 +2174,7 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
if (!validator.isNonEmptyString(tenantId)) {
return Promise.reject(new FirebaseAuthError(AuthClientErrorCode.INVALID_TENANT_ID));
}
return this.invokeRequestHandler(this.tenantMgmtResourceBuilder, DELETE_TENANT, undefined, { tenantId })
return this.invokeRequestHandler(this.authResourceUrlBuilder, DELETE_TENANT, undefined, { tenantId })
.then(() => {
// Return nothing.
});
Expand All @@ -2138,7 +2190,7 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
try {
// Construct backend request.
const request = Tenant.buildServerRequest(tenantOptions, true);
return this.invokeRequestHandler(this.tenantMgmtResourceBuilder, CREATE_TENANT, request)
return this.invokeRequestHandler(this.authResourceUrlBuilder, CREATE_TENANT, request)
.then((response: any) => {
return response as TenantServerResponse;
});
Expand All @@ -2164,7 +2216,7 @@ export class AuthRequestHandler extends AbstractAuthRequestHandler {
// Do not traverse deep into testPhoneNumbers. The entire content should be replaced
// and not just specific phone numbers.
const updateMask = utils.generateUpdateMask(request, ['testPhoneNumbers']);
return this.invokeRequestHandler(this.tenantMgmtResourceBuilder, UPDATE_TENANT, request,
return this.invokeRequestHandler(this.authResourceUrlBuilder, UPDATE_TENANT, request,
{ tenantId, updateMask: updateMask.join(',') })
.then((response: any) => {
return response as TenantServerResponse;
Expand Down
Loading