Skip to content
130 changes: 119 additions & 11 deletions spec/common/providers/identity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import * as identity from "../../../src/common/providers/identity";

const EVENT = "EVENT_TYPE";
const now = new Date();
const TEST_NAME = "John Doe";
const ALLOW = "ALLOW";
const BLOCK = "BLOCK";

describe("identity", () => {
describe("userRecordConstructor", () => {
Expand Down Expand Up @@ -232,14 +235,14 @@ describe("identity", () => {
describe("parseProviderData", () => {
const decodedUserInfo = {
provider_id: "google.com",
display_name: "John Doe",
display_name: TEST_NAME,
photo_url: "https://lh3.googleusercontent.com/1234567890/photo.jpg",
uid: "1234567890",
email: "user@gmail.com",
};
const userInfo = {
providerId: "google.com",
displayName: "John Doe",
displayName: TEST_NAME,
photoURL: "https://lh3.googleusercontent.com/1234567890/photo.jpg",
uid: "1234567890",
email: "user@gmail.com",
Expand Down Expand Up @@ -340,12 +343,12 @@ describe("identity", () => {
uid: "abcdefghijklmnopqrstuvwxyz",
email: "user@gmail.com",
email_verified: true,
display_name: "John Doe",
display_name: TEST_NAME,
phone_number: "+11234567890",
provider_data: [
{
provider_id: "google.com",
display_name: "John Doe",
display_name: TEST_NAME,
photo_url: "https://lh3.googleusercontent.com/1234567890/photo.jpg",
email: "user@gmail.com",
uid: "1234567890",
Expand All @@ -366,7 +369,7 @@ describe("identity", () => {
provider_id: "password",
email: "user@gmail.com",
uid: "user@gmail.com",
display_name: "John Doe",
display_name: TEST_NAME,
},
],
password_hash: "passwordHash",
Expand Down Expand Up @@ -407,11 +410,11 @@ describe("identity", () => {
phoneNumber: "+11234567890",
emailVerified: true,
disabled: false,
displayName: "John Doe",
displayName: TEST_NAME,
providerData: [
{
providerId: "google.com",
displayName: "John Doe",
displayName: TEST_NAME,
photoURL: "https://lh3.googleusercontent.com/1234567890/photo.jpg",
email: "user@gmail.com",
uid: "1234567890",
Expand All @@ -435,7 +438,7 @@ describe("identity", () => {
},
{
providerId: "password",
displayName: "John Doe",
displayName: TEST_NAME,
photoURL: undefined,
email: "user@gmail.com",
uid: "user@gmail.com",
Expand Down Expand Up @@ -489,8 +492,9 @@ describe("identity", () => {
});

describe("parseAuthEventContext", () => {
const TEST_RECAPTCHA_SCORE = 0.9;
const rawUserInfo = {
name: "John Doe",
name: TEST_NAME,
granted_scopes:
"openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile",
id: "123456789",
Expand All @@ -516,13 +520,15 @@ describe("identity", () => {
user_agent: "USER_AGENT",
locale: "en",
raw_user_info: JSON.stringify(rawUserInfo),
recaptcha_score: TEST_RECAPTCHA_SCORE,
};
const context = {
locale: "en",
ipAddress: "1.2.3.4",
userAgent: "USER_AGENT",
eventId: "EVENT_ID",
eventType: EVENT,
emailType: undefined,
authType: "UNAUTHENTICATED",
resource: {
service: "identitytoolkit.googleapis.com",
Expand All @@ -534,6 +540,8 @@ describe("identity", () => {
profile: rawUserInfo,
username: undefined,
isNewUser: false,
recaptchaScore: TEST_RECAPTCHA_SCORE,
email: undefined,
},
credential: null,
params: {},
Expand Down Expand Up @@ -563,13 +571,15 @@ describe("identity", () => {
oauth_refresh_token: "REFRESH_TOKEN",
oauth_token_secret: "OAUTH_TOKEN_SECRET",
oauth_expires_in: 3600,
recaptcha_score: TEST_RECAPTCHA_SCORE,
};
const context = {
locale: "en",
ipAddress: "1.2.3.4",
userAgent: "USER_AGENT",
eventId: "EVENT_ID",
eventType: "providers/cloud.auth/eventTypes/user.beforeSignIn:password",
emailType: undefined,
authType: "UNAUTHENTICATED",
resource: {
service: "identitytoolkit.googleapis.com",
Expand All @@ -581,6 +591,8 @@ describe("identity", () => {
profile: rawUserInfo,
username: undefined,
isNewUser: false,
recaptchaScore: TEST_RECAPTCHA_SCORE,
email: undefined,
},
credential: {
claims: undefined,
Expand Down Expand Up @@ -619,14 +631,14 @@ describe("identity", () => {
uid: "abcdefghijklmnopqrstuvwxyz",
email: "user@gmail.com",
email_verified: true,
display_name: "John Doe",
display_name: TEST_NAME,
phone_number: "+11234567890",
provider_data: [
{
provider_id: "oidc.provider",
email: "user@gmail.com",
uid: "user@gmail.com",
display_name: "John Doe",
display_name: TEST_NAME,
},
],
photo_url: "https://lh3.googleusercontent.com/1234567890/photo.jpg",
Expand All @@ -647,13 +659,15 @@ describe("identity", () => {
oauth_token_secret: "OAUTH_TOKEN_SECRET",
oauth_expires_in: 3600,
raw_user_info: JSON.stringify(rawUserInfo),
recaptcha_score: TEST_RECAPTCHA_SCORE,
};
const context = {
locale: "en",
ipAddress: "1.2.3.4",
userAgent: "USER_AGENT",
eventId: "EVENT_ID",
eventType: "providers/cloud.auth/eventTypes/user.beforeCreate:oidc.provider",
emailType: undefined,
authType: "USER",
resource: {
service: "identitytoolkit.googleapis.com",
Expand All @@ -665,6 +679,8 @@ describe("identity", () => {
providerId: "oidc.provider",
profile: rawUserInfo,
isNewUser: true,
recaptchaScore: TEST_RECAPTCHA_SCORE,
email: undefined,
},
credential: {
claims: undefined,
Expand All @@ -681,6 +697,50 @@ describe("identity", () => {

expect(identity.parseAuthEventContext(decodedJwt, "project-id", time)).to.deep.equal(context);
});

it("should parse a beforeSendEmail event", () => {
const time = now.getTime();
const decodedJwt = {
iss: "https://securetoken.google.com/project_id",
aud: "https://us-east1-project_id.cloudfunctions.net/function-1",
iat: 1,
exp: 60 * 60 + 1,
event_id: "EVENT_ID",
event_type: "beforeSendEmail",
user_agent: "USER_AGENT",
ip_address: "1.2.3.4",
locale: "en",
recaptcha_score: TEST_RECAPTCHA_SCORE,
email_type: "RESET_PASSWORD",
email: "johndoe@gmail.com",
};
const context = {
locale: "en",
ipAddress: "1.2.3.4",
userAgent: "USER_AGENT",
eventId: "EVENT_ID",
eventType: "providers/cloud.auth/eventTypes/user.beforeSendEmail",
emailType: "RESET_PASSWORD",
authType: "UNAUTHENTICATED",
resource: {
service: "identitytoolkit.googleapis.com",
name: "projects/project-id",
},
timestamp: new Date(1000).toUTCString(),
additionalUserInfo: {
isNewUser: false,
profile: undefined,
providerId: undefined,
username: undefined,
recaptchaScore: TEST_RECAPTCHA_SCORE,
email: "johndoe@gmail.com",
},
credential: null,
params: {},
};

expect(identity.parseAuthEventContext(decodedJwt, "project-id", time)).to.deep.equal(context);
});
});

describe("validateAuthResponse", () => {
Expand Down Expand Up @@ -762,4 +822,52 @@ describe("identity", () => {
);
});
});

describe("generateResponsePayload", () => {
const DISPLAY_NAME_FIELD = "displayName";
const TEST_RESPONSE = {
displayName: TEST_NAME,
recaptchaActionOverride: BLOCK,
} as identity.BeforeCreateResponse;

const EXPECT_PAYLOAD = {
userRecord: { displayName: TEST_NAME, updateMask: DISPLAY_NAME_FIELD },
recaptchaActionOverride: BLOCK,
};

const TEST_RESPONSE_RECAPTCHA_ALLOW = {
recaptchaActionOverride: ALLOW,
} as identity.BeforeCreateResponse;

const EXPECT_PAYLOAD_RECAPTCHA_ALLOW = {
recaptchaActionOverride: ALLOW,
};

const TEST_RESPONSE_RECAPTCHA_UNDEFINED = {
displayName: TEST_NAME,
} as identity.BeforeSignInResponse;

const EXPECT_PAYLOAD_UNDEFINED = {
userRecord: { displayName: TEST_NAME, updateMask: DISPLAY_NAME_FIELD },
};
it("should return empty object on undefined response", () => {
expect(identity.generateResponsePayload()).to.eql({});
});

it("should exclude recaptchaActionOverride field from updateMask", () => {
expect(identity.generateResponsePayload(TEST_RESPONSE)).to.deep.equal(EXPECT_PAYLOAD);
});

it("should return recaptchaActionOverride when it is true on response", () => {
expect(identity.generateResponsePayload(TEST_RESPONSE_RECAPTCHA_ALLOW)).to.deep.equal(
EXPECT_PAYLOAD_RECAPTCHA_ALLOW
);
});

it("should not return recaptchaActionOverride if undefined", () => {
const payload = identity.generateResponsePayload(TEST_RESPONSE_RECAPTCHA_UNDEFINED);
expect(payload.hasOwnProperty("recaptchaActionOverride")).to.be.false;
expect(payload).to.deep.equal(EXPECT_PAYLOAD_UNDEFINED);
});
});
});
90 changes: 90 additions & 0 deletions spec/v1/providers/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,96 @@ describe("Auth Functions", () => {
});
});

describe("beforeEmail", () => {
it("should create function without options", () => {
const fn = auth.user().beforeEmail(() => Promise.resolve());

expect(fn.__trigger).to.deep.equal({
labels: {},
blockingTrigger: {
eventType: "providers/cloud.auth/eventTypes/user.beforeSendEmail",
options: {
accessToken: false,
idToken: false,
refreshToken: false,
},
},
});
expect(fn.__endpoint).to.deep.equal({
...MINIMAL_V1_ENDPOINT,
platform: "gcfv1",
labels: {},
blockingTrigger: {
eventType: "providers/cloud.auth/eventTypes/user.beforeSendEmail",
options: {
accessToken: false,
idToken: false,
refreshToken: false,
},
},
});
expect(fn.__requiredAPIs).to.deep.equal([
{
api: "identitytoolkit.googleapis.com",
reason: "Needed for auth blocking functions",
},
]);
});

it("should create the function with options", () => {
const fn = functions
.region("us-east1")
.runWith({
timeoutSeconds: 90,
memory: "256MB",
})
.auth.user({
blockingOptions: {
accessToken: true,
refreshToken: false,
},
})
.beforeEmail(() => Promise.resolve());

expect(fn.__trigger).to.deep.equal({
labels: {},
regions: ["us-east1"],
availableMemoryMb: 256,
timeout: "90s",
blockingTrigger: {
eventType: "providers/cloud.auth/eventTypes/user.beforeSendEmail",
options: {
accessToken: true,
idToken: false,
refreshToken: false,
},
},
});
expect(fn.__endpoint).to.deep.equal({
...MINIMAL_V1_ENDPOINT,
platform: "gcfv1",
labels: {},
region: ["us-east1"],
availableMemoryMb: 256,
timeoutSeconds: 90,
blockingTrigger: {
eventType: "providers/cloud.auth/eventTypes/user.beforeSendEmail",
options: {
accessToken: true,
idToken: false,
refreshToken: false,
},
},
});
expect(fn.__requiredAPIs).to.deep.equal([
{
api: "identitytoolkit.googleapis.com",
reason: "Needed for auth blocking functions",
},
]);
});
});

describe("#_dataConstructor", () => {
let cloudFunctionDelete: CloudFunction<UserRecord>;

Expand Down
Loading