Skip to content

Commit

Permalink
Move common auth items into common path (#1026)
Browse files Browse the repository at this point in the history
* moving common auth items to identity.ts and fixing UserRecord definitions

* fixing copyright year and exporting old artifacts
  • Loading branch information
colerogers authored Feb 2, 2022
1 parent 297b15b commit af2c516
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 155 deletions.
88 changes: 88 additions & 0 deletions spec/common/providers/identity.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Firebase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { expect } from 'chai';
import * as identity from '../../../src/common/providers/identity';

describe('identity', () => {
describe('userRecordConstructor', () => {
it('will provide falsey values for fields that are not in raw wire data', () => {
const record = identity.userRecordConstructor({ uid: '123' });
expect(record.toJSON()).to.deep.equal({
uid: '123',
email: null,
emailVerified: false,
displayName: null,
photoURL: null,
phoneNumber: null,
disabled: false,
providerData: [],
customClaims: {},
passwordSalt: null,
passwordHash: null,
tokensValidAfterTime: null,
metadata: {
creationTime: null,
lastSignInTime: null,
},
});
});

it('will not interfere with fields that are in raw wire data', () => {
const raw: any = {
uid: '123',
email: 'email@gmail.com',
emailVerified: true,
displayName: 'User',
photoURL: 'url',
phoneNumber: '1233332222',
disabled: true,
providerData: [],
customClaims: {},
passwordSalt: 'abc',
passwordHash: 'def',
tokensValidAfterTime: '2027-02-02T23:01:19.797Z',
metadata: {
creationTime: '2017-02-02T23:06:26.124Z',
lastSignInTime: '2017-02-02T23:01:19.797Z',
},
};
const record = identity.userRecordConstructor(raw);
expect(record.toJSON()).to.deep.equal(raw);
});

it('will convert raw wire fields createdAt and lastSignedInAt to creationTime and lastSignInTime', () => {
const raw: any = {
uid: '123',
metadata: {
createdAt: '2017-02-02T23:06:26.124Z',
lastSignedInAt: '2017-02-02T23:01:19.797Z',
},
};
const record = identity.userRecordConstructor(raw);
expect(record.metadata).to.deep.equal({
creationTime: '2017-02-02T23:06:26.124Z',
lastSignInTime: '2017-02-02T23:01:19.797Z',
});
});
});
});
77 changes: 6 additions & 71 deletions spec/v1/providers/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
// SOFTWARE.

import { expect } from 'chai';
import * as firebase from 'firebase-admin';

import {
CloudFunction,
Event,
EventContext,
} from '../../../src/cloud-functions';
import { UserRecord } from '../../../src/common/providers/identity';
import * as functions from '../../../src/index';
import * as auth from '../../../src/providers/auth';

Expand Down Expand Up @@ -75,7 +74,7 @@ describe('Auth Functions', () => {
};
}

const handler = (user: firebase.auth.UserRecord) => {
const handler = (user: UserRecord) => {
return Promise.resolve();
};

Expand Down Expand Up @@ -137,14 +136,12 @@ describe('Auth Functions', () => {
});

describe('#_dataConstructor', () => {
let cloudFunctionDelete: CloudFunction<firebase.auth.UserRecord>;
let cloudFunctionDelete: CloudFunction<UserRecord>;

before(() => {
cloudFunctionDelete = auth
.user()
.onDelete(
(data: firebase.auth.UserRecord, context: EventContext) => data
);
.onDelete((data: UserRecord, context: EventContext) => data);
});

it('should handle wire format as of v5.0.0 of firebase-admin', () => {
Expand All @@ -162,68 +159,6 @@ describe('Auth Functions', () => {
});
});

describe('userRecordConstructor', () => {
it('will provide falsey values for fields that are not in raw wire data', () => {
const record = auth.userRecordConstructor({ uid: '123' });
expect(record.toJSON()).to.deep.equal({
uid: '123',
email: null,
emailVerified: false,
displayName: null,
photoURL: null,
phoneNumber: null,
disabled: false,
providerData: [],
customClaims: {},
passwordSalt: null,
passwordHash: null,
tokensValidAfterTime: null,
metadata: {
creationTime: null,
lastSignInTime: null,
},
});
});

it('will not interfere with fields that are in raw wire data', () => {
const raw: any = {
uid: '123',
email: 'email@gmail.com',
emailVerified: true,
displayName: 'User',
photoURL: 'url',
phoneNumber: '1233332222',
disabled: true,
providerData: [],
customClaims: {},
passwordSalt: 'abc',
passwordHash: 'def',
tokensValidAfterTime: '2027-02-02T23:01:19.797Z',
metadata: {
creationTime: '2017-02-02T23:06:26.124Z',
lastSignInTime: '2017-02-02T23:01:19.797Z',
},
};
const record = auth.userRecordConstructor(raw);
expect(record.toJSON()).to.deep.equal(raw);
});

it('will convert raw wire fields createdAt and lastSignedInAt to creationTime and lastSignInTime', () => {
const raw: any = {
uid: '123',
metadata: {
createdAt: '2017-02-02T23:06:26.124Z',
lastSignedInAt: '2017-02-02T23:01:19.797Z',
},
};
const record = auth.userRecordConstructor(raw);
expect(record.metadata).to.deep.equal({
creationTime: '2017-02-02T23:06:26.124Z',
lastSignInTime: '2017-02-02T23:01:19.797Z',
});
});
});

describe('handler namespace', () => {
describe('#onCreate', () => {
it('should return an empty trigger', () => {
Expand All @@ -238,8 +173,8 @@ describe('Auth Functions', () => {
});

describe('#onDelete', () => {
const cloudFunctionDelete: CloudFunction<firebase.auth.UserRecord> = functions.handler.auth.user.onDelete(
(data: firebase.auth.UserRecord) => data
const cloudFunctionDelete: CloudFunction<UserRecord> = functions.handler.auth.user.onDelete(
(data: UserRecord) => data
);

it('should return an empty trigger', () => {
Expand Down
111 changes: 111 additions & 0 deletions src/common/providers/identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Firebase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import * as firebase from 'firebase-admin';
import * as _ from 'lodash';

/**
* The UserRecord passed to Cloud Functions is the same UserRecord that is returned by the Firebase Admin
* SDK.
*/
export type UserRecord = firebase.auth.UserRecord;

/**
* UserInfo that is part of the UserRecord
*/
export type UserInfo = firebase.auth.UserInfo;

/**
* Helper class to create the user metadata in a UserRecord object
*/
export class UserRecordMetadata implements firebase.auth.UserMetadata {
constructor(public creationTime: string, public lastSignInTime: string) {}

/** Returns a plain JavaScript object with the properties of UserRecordMetadata. */
toJSON() {
return {
creationTime: this.creationTime,
lastSignInTime: this.lastSignInTime,
};
}
}

/**
* Helper function that creates a UserRecord Class from data sent over the wire.
* @param wireData data sent over the wire
* @returns an instance of UserRecord with correct toJSON functions
*/
export function userRecordConstructor(wireData: Object): UserRecord {
// Falsey values from the wire format proto get lost when converted to JSON, this adds them back.
const falseyValues: any = {
email: null,
emailVerified: false,
displayName: null,
photoURL: null,
phoneNumber: null,
disabled: false,
providerData: [],
customClaims: {},
passwordSalt: null,
passwordHash: null,
tokensValidAfterTime: null,
};
const record = _.assign({}, falseyValues, wireData);

const meta = _.get(record, 'metadata');
if (meta) {
_.set(
record,
'metadata',
new UserRecordMetadata(
meta.createdAt || meta.creationTime,
meta.lastSignedInAt || meta.lastSignInTime
)
);
} else {
_.set(record, 'metadata', new UserRecordMetadata(null, null));
}
_.forEach(record.providerData, (entry) => {
_.set(entry, 'toJSON', () => {
return entry;
});
});
_.set(record, 'toJSON', () => {
const json: any = _.pick(record, [
'uid',
'email',
'emailVerified',
'displayName',
'photoURL',
'phoneNumber',
'disabled',
'passwordHash',
'passwordSalt',
'tokensValidAfterTime',
]);
json.metadata = _.get(record, 'metadata').toJSON();
json.customClaims = _.cloneDeep(record.customClaims);
json.providerData = _.map(record.providerData, (entry) => entry.toJSON());
return json;
});
return record as UserRecord;
}
Loading

0 comments on commit af2c516

Please sign in to comment.