diff --git a/docs/articles/auth/firebase-authentication.md b/docs/articles/auth/firebase-authentication.md new file mode 100644 index 0000000000..e24a2a878d --- /dev/null +++ b/docs/articles/auth/firebase-authentication.md @@ -0,0 +1,190 @@ +## Firebase authentication with Nebular Auth + +`@nebualar/firebase-auth` allows authentication in firebase applications with `@nebular/auth`. +The package provides the following strategies: + - `NbFirebasePasswordStrategy` - authentication with email/password + - `NbFirebaseGoogleStrategy` - authentication with google accounts + - `NbFirebaseFacebookStrategy` - authentication with facebook accounts + - `NbFirebaseTwitteStrategy` - authentication with twitter accounts + +`@nebular/auth` package is sponsored by [GO-ER](www.go-er.com) and What Now Travel. + +## Installation + +
+
Note
+
+ The package connects firebase auth with nebular/auth so you need `firebase` and `@angular/fire` installed + and configured for your application. For more instructions please see [@angular/fire docs](https://github.com/akveo/nebular/tree/master/src/playground/without-layout/azure). + Also make sure you import AngularFireAuthModule. +
+
+ + +Install Nebular Auth and Nebular Firebase Auth. + + ```sh + npm i @nebular/auth @angular\firebase-auth + ``` + +Import the NbAuthModule with some firebase strategies, in that example we use NbFirebasePasswordStrategy. + +```ts +import { NbAuthModule } from '@nebular/auth'; +import { NbFirebasePasswordStrategy } from '@nebular/firebase-auth'; + + +@NgModule({ + imports: [ + // ... + + NbAuthModule.forRoot({ + strategies: [ + NbFirebasePasswordStrategy.setup({ + name: 'password', + }), + ], + forms: {}, + }), + ], +}); +``` +
+ +## Authentication with email and password + +Nebular Firebase Auth provides NbFirebasePassword strategy for authentication with email and password. + +Strategy settings: +
+
Note
+
+ There is no need to copy over the whole object to change the settings you need. + Also, this.getOption call won't work outside of the default options declaration (which is inside of the NbPasswordAuthStrategy class), + so you have to replace it with a custom helper function if you need it. +
+
+ +```ts +export class NbFirebasePasswordStrategyOptions extends NbAuthStrategyOptions { + name: string; + token = { + class: NbAuthJWTToken, + }; + register?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully registered.'], + }; + login?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Login/Email combination is not correct, please try again.'], + defaultMessages: ['You have been successfully logged in.'], + }; + logout?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully logged out.'], + }; + refreshToken?: boolean | NbPasswordStrategyModule = { + redirect: { + success: null, + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['Your token has been successfully refreshed.'], + }; + requestPassword?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['Reset password instructions have been sent to your email.'], + }; + resetPassword?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['Your password has been successfully changed.'], + }; + errors?: NbPasswordStrategyMessage = { + key: 'message', + getter: (module: string, res, options: NbFirebasePasswordStrategyOptions) => getDeepFromObject( + res, + options.errors.key, + options[module].defaultErrors, + ), + }; + messages?: NbPasswordStrategyMessage = { + key: 'messages', + getter: (module: string, res, options: NbFirebasePasswordStrategyOptions) => getDeepFromObject( + res.body, + options.messages.key, + options[module].defaultMessages, + ), + }; +} +``` +
+ +## Social Authentication providers + +Nebular Firebase Auth for now provides strategies for authentication with Google, Facebook and Twitter. +These strategies share the same settings structure and default settings value. + +Strategies settings: + +```ts +export class NbFirebaseIdentityProviderStrategyOptions extends NbAuthStrategyOptions { + name: string; + logout?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully logged out.'], + }; + authenticate?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully authenticated.'], + }; + errors?: NbPasswordStrategyMessage = { + key: 'message', + getter: (module: string, res, options: NbFirebaseIdentityProviderStrategyOptions) => options[module].defaultErrors, + }; + messages?: NbPasswordStrategyMessage = { + key: 'message', + getter: (module: string, res, options: NbFirebaseIdentityProviderStrategyOptions) => options[module].defaultMessages, + }; + scopes?: string[] = []; + customParameters?: { [key: string]: string } = {}; + } +}; +``` +
+ +## Complete example + +A complete code example could be found on [GitHub](https://github.com/akveo/nebular/tree/master/src/playground/with-layout/firebase). + +And here the playground examples available to play around with + - [Firebase Nebular Password Example](/example/firebase/password-showcase) + - [Firebase Nebular Social Authentication Providers Example](/example/firebase/social-auth-showcase) + diff --git a/docs/articles/getting-started/what-is-nebular.md b/docs/articles/getting-started/what-is-nebular.md index e3f8f83f58..dd4bdfff92 100644 --- a/docs/articles/getting-started/what-is-nebular.md +++ b/docs/articles/getting-started/what-is-nebular.md @@ -16,6 +16,8 @@ Nebular modules are distributed as separated `npm` packages: - Authentication components (login/register/reset password/restore password). - Multiple configurable authentication Strategies (backend connectors). - Helpers for token management (storing, passing with HTTP requests, etc). +- Nebular Auth for Firebase `@nebular/firebase-auth + - module for authentication in firebase applications with nebular/auth - Nebular Security `@nebular/security` - roles and permissions management. - Nebular Moment `@nebular/moment` diff --git a/docs/structure.ts b/docs/structure.ts index 03832e576a..3373c6c787 100644 --- a/docs/structure.ts +++ b/docs/structure.ts @@ -915,6 +915,17 @@ export const structure = [ }, ], }, + { + type: 'page', + name: 'Firebase Authentication', + children: [ + { + type: 'block', + block: 'markdown', + source: 'auth/firebase-authentication.md', + }, + ], + }, { type: 'page', name: 'NbAuthService', diff --git a/docs/tsconfig.app.json b/docs/tsconfig.app.json index 15ffc4f06c..86841ae302 100644 --- a/docs/tsconfig.app.json +++ b/docs/tsconfig.app.json @@ -18,7 +18,8 @@ "@nebular/theme": ["../src/framework/theme/public_api.ts"], "@nebular/auth": ["../src/framework/auth/public_api.ts"], "@nebular/security": ["../src/framework/security/public_api.ts"], - "@nebular/eva-icons": ["../src/framework/eva-icons/public_api.ts"] + "@nebular/eva-icons": ["../src/framework/eva-icons/public_api.ts"], + "@nebular/firebase-auth": ["../src/framework/firebase-auth/public_api.ts"] } }, "files": [ diff --git a/package-lock.json b/package-lock.json index 3f1c075cd8..3273823321 100644 --- a/package-lock.json +++ b/package-lock.json @@ -937,6 +937,11 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.4.tgz", "integrity": "sha512-6RqQb1GO2uglSlgiGbxhvy8plztZtABCWLRn0X+T1PnrxoqgxqA5WkKJjGxao+1M/ECW1V0fw4Xy7DE6KvAJwQ==" }, + "@angular/fire": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@angular/fire/-/fire-6.0.0.tgz", + "integrity": "sha512-zWhaJaZPtfJKiNSb1I3WqqvopW0fN3S61w4PjPdsm5WME+9M9alP0zpRVclpbCU26LpBSLhrRrSLyn3ROlAOIw==" + }, "@angular/forms": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.0.4.tgz", @@ -2187,6 +2192,348 @@ } } }, + "@firebase/analytics": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.3.5.tgz", + "integrity": "sha512-p+h1s9A8EjGWfjAObu8ei46JoN2Ogbtl1RzqW7HjcPuclOIOmPTXKEXXCEXgO79OLxnzzezVeBtHPSx6r6gxJA==", + "requires": { + "@firebase/analytics-types": "0.3.1", + "@firebase/component": "0.1.12", + "@firebase/installations": "0.4.10", + "@firebase/logger": "0.2.4", + "@firebase/util": "0.2.47", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/analytics-types": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.3.1.tgz", + "integrity": "sha512-63vVJ5NIBh/JF8l9LuPrQYSzFimk7zYHySQB4Dk9rVdJ8kV/vGQoVTvRu1UW05sEc2Ug5PqtEChtTHU+9hvPcA==" + }, + "@firebase/app": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.6.4.tgz", + "integrity": "sha512-E1Zw6yeZYdYYFurMnklKPvE+q/xleHXs7bmcVgyhgAEg3Gv6/qXI4+4GdWh+iF7wmQ3Liesh51xqfdpvHBwAMQ==", + "requires": { + "@firebase/app-types": "0.6.1", + "@firebase/component": "0.1.12", + "@firebase/logger": "0.2.4", + "@firebase/util": "0.2.47", + "dom-storage": "2.1.0", + "tslib": "1.11.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/app-types": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.6.1.tgz", + "integrity": "sha512-L/ZnJRAq7F++utfuoTKX4CLBG5YR7tFO3PLzG1/oXXKEezJ0kRL3CMRoueBEmTCzVb/6SIs2Qlaw++uDgi5Xyg==" + }, + "@firebase/auth": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.14.6.tgz", + "integrity": "sha512-7gaEUWhUubWBGfOXAZvpTpJqBJT9KyG83RXC6VnjSQIfNUaarHZ485WkzERil43A6KvIl+f4kHxfZShE6ZCK3A==", + "requires": { + "@firebase/auth-types": "0.10.1" + } + }, + "@firebase/auth-interop-types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.5.tgz", + "integrity": "sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==" + }, + "@firebase/auth-types": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.10.1.tgz", + "integrity": "sha512-/+gBHb1O9x/YlG7inXfxff/6X3BPZt4zgBv4kql6HEmdzNQCodIRlEYnI+/da+lN+dha7PjaFH7C7ewMmfV7rw==" + }, + "@firebase/component": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.12.tgz", + "integrity": "sha512-03w800MxR/EW1m7N0Q46WNcngwdDIHDWpFPHTdbZEI6U/HuLks5RJQlBxWqb1P73nYPkN8YP3U8gTdqrDpqY3Q==", + "requires": { + "@firebase/util": "0.2.47", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/database": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.3.tgz", + "integrity": "sha512-gHoCISHQVLoq+rGu+PorYxMkhsjhXov3ocBxz/0uVdznNhrbKkAZaEKF+dIAsUPDlwSYeZuwWuik7xcV3DtRaw==", + "requires": { + "@firebase/auth-interop-types": "0.1.5", + "@firebase/component": "0.1.12", + "@firebase/database-types": "0.5.1", + "@firebase/logger": "0.2.4", + "@firebase/util": "0.2.47", + "faye-websocket": "0.11.3", + "tslib": "1.11.1" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/database-types": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.5.1.tgz", + "integrity": "sha512-onQxom1ZBYBJ648w/VNRzUewovEDAH7lvnrrpCd69ukkyrMk6rGEO/PQ9BcNEbhlNtukpsqRS0oNOFlHs0FaSA==", + "requires": { + "@firebase/app-types": "0.6.1" + } + }, + "@firebase/firestore": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.14.5.tgz", + "integrity": "sha512-BZD3RqlAEnq15i8Y53VUFsuWkbujslGaQIcuEnt6bOENzlKiLBwESmt/uGKRIsdQjc1krG2qdoPmaSMqULR0dA==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/firestore-types": "1.10.2", + "@firebase/logger": "0.2.4", + "@firebase/util": "0.2.47", + "@firebase/webchannel-wrapper": "0.2.41", + "@grpc/grpc-js": "0.8.1", + "@grpc/proto-loader": "^0.5.0", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/firestore-types": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-1.10.2.tgz", + "integrity": "sha512-T1GttZezQ+gUpdDgLeLOvgS3KMeeIuodQ+JBBEd6M11zdilfTHsEHhmli15c6V3g/PfuFzyKDKExe05lPuYe4w==" + }, + "@firebase/functions": { + "version": "0.4.44", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.44.tgz", + "integrity": "sha512-Nbw+V/jYqfgq7wscsSDidqIzx8TrnmA2wRD1auCFNmf+gSJg8o+gNyCDdNHZI407jvrZcxp3nG1eMbqwmmnp7Q==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/functions-types": "0.3.17", + "@firebase/messaging-types": "0.4.5", + "isomorphic-fetch": "2.2.1", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/functions-types": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.3.17.tgz", + "integrity": "sha512-DGR4i3VI55KnYk4IxrIw7+VG7Q3gA65azHnZxo98Il8IvYLr2UTBlSh72dTLlDf25NW51HqvJgYJDKvSaAeyHQ==" + }, + "@firebase/installations": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.4.10.tgz", + "integrity": "sha512-Nf7VK9++0eQzjdvBkBNNaOdxPjFiKD0EllLCIQycHozF97BmuFUqb2Ik5L2JaWspWg7vxLNacLHvW48nPGx4Zw==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/installations-types": "0.3.4", + "@firebase/util": "0.2.47", + "idb": "3.0.2", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/installations-types": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.3.4.tgz", + "integrity": "sha512-RfePJFovmdIXb6rYwtngyxuEcWnOrzdZd9m7xAW0gRxDIjBT20n3BOhjpmgRWXo/DAxRmS7bRjWAyTHY9cqN7Q==" + }, + "@firebase/logger": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.4.tgz", + "integrity": "sha512-akHkOU7izYB1okp/B5sxClGjjw6KvZdSHyjNM5pKd67Zg5W6PsbkI/GFNv21+y6LkUkJwDRbdeDgJoYXWT3mMA==" + }, + "@firebase/messaging": { + "version": "0.6.16", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.6.16.tgz", + "integrity": "sha512-TAPISK5y3xbxUw81HxLDP6YPsRryU6Nl8Z7AjNnem13BoN9LJ2/wCi9RDMfPnQhAn0h0N+mpxy/GB+0IlEARlg==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/installations": "0.4.10", + "@firebase/messaging-types": "0.4.5", + "@firebase/util": "0.2.47", + "idb": "3.0.2", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/messaging-types": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@firebase/messaging-types/-/messaging-types-0.4.5.tgz", + "integrity": "sha512-sux4fgqr/0KyIxqzHlatI04Ajs5rc3WM+WmtCpxrKP1E5Bke8xu/0M+2oy4lK/sQ7nov9z15n3iltAHCgTRU3Q==" + }, + "@firebase/performance": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.3.4.tgz", + "integrity": "sha512-VDoqJSB+2RuXlyyP7oSvBPEmoznG84HmEtb8DQWsAHeVkf+qlec1OTZR8IjktlIv+8Pg8MMuYoB0crx5g7xU5A==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/installations": "0.4.10", + "@firebase/logger": "0.2.4", + "@firebase/performance-types": "0.0.13", + "@firebase/util": "0.2.47", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/performance-types": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.0.13.tgz", + "integrity": "sha512-6fZfIGjQpwo9S5OzMpPyqgYAUZcFzZxHFqOyNtorDIgNXq33nlldTL/vtaUZA8iT9TT5cJlCrF/jthKU7X21EA==" + }, + "@firebase/polyfill": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.36.tgz", + "integrity": "sha512-zMM9oSJgY6cT2jx3Ce9LYqb0eIpDE52meIzd/oe/y70F+v9u1LDqk5kUF5mf16zovGBWMNFmgzlsh6Wj0OsFtg==", + "requires": { + "core-js": "3.6.5", + "promise-polyfill": "8.1.3", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" + }, + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + } + } + }, + "@firebase/remote-config": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.1.21.tgz", + "integrity": "sha512-EwDNU1mT+8Jn66IUwwNP5SM8AbaI7wmCXjp7djZtTXNrpPoh3xqzSRM1vTgp4Uu/mHffEDfbydsoJAIftADIfQ==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/installations": "0.4.10", + "@firebase/logger": "0.2.4", + "@firebase/remote-config-types": "0.1.9", + "@firebase/util": "0.2.47", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/remote-config-types": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.1.9.tgz", + "integrity": "sha512-G96qnF3RYGbZsTRut7NBX0sxyczxt1uyCgXQuH/eAfUCngxjEGcZQnBdy6mvSdqdJh5mC31rWPO4v9/s7HwtzA==" + }, + "@firebase/storage": { + "version": "0.3.34", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.34.tgz", + "integrity": "sha512-vuR1PpGdaCk25D2dT2trfmZZjpdfOn0rPTksvoqg7TAPLeoVsVoDyT2LgF3Arna/jqx52sAIRx1HLrlvzE1pgA==", + "requires": { + "@firebase/component": "0.1.12", + "@firebase/storage-types": "0.3.12", + "@firebase/util": "0.2.47", + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/storage-types": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.3.12.tgz", + "integrity": "sha512-DDV6Fs6aYoGw3w/zZZTkqiipxihnsvHf6znbeZYjIIHit3tr1uLJdGPDPiCTfZcTGPpg2ux6ZmvNDvVgJdHALw==" + }, + "@firebase/util": { + "version": "0.2.47", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.47.tgz", + "integrity": "sha512-RjcIvcfswyxYhf0OMXod+qeI/933wl9FGLIszf0/O1yMZ/s8moXcse7xnOpMjmQPRLB9vHzCMoxW5X90kKg/bQ==", + "requires": { + "tslib": "1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + } + } + }, + "@firebase/webchannel-wrapper": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.41.tgz", + "integrity": "sha512-XcdMT5PSZHiuf7LJIhzKIe+RyYa25S3LHRRvLnZc6iFjwXkrSDJ8J/HWO6VT8d2ZTbawp3VcLEjRF/VN8glCrA==" + }, "@google-cloud/common": { "version": "0.17.0", "resolved": "http://registry.npmjs.org/@google-cloud/common/-/common-0.17.0.tgz", @@ -2620,6 +2967,30 @@ } } }, + "@grpc/grpc-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.8.1.tgz", + "integrity": "sha512-e8gSjRZnOUefsR3obOgxG9RtYW2Mw83hh7ogE2ByCdgRhoX0mdnJwBcZOami3E0l643KCTZvORFwfSEi48KFIQ==", + "requires": { + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@grpc/proto-loader": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.4.tgz", + "integrity": "sha512-HTM4QpI9B2XFkPz7pjwMyMgZchJ93TVkL3kWPW8GDMDKYxsMnmf4w2TNMJK7+KNiYHS5cJrCEAFlF+AwtXWVPA==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, "@gulp-sourcemaps/identity-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", @@ -2740,6 +3111,60 @@ "esquery": "^1.0.1" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@schematics/angular": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-9.0.1.tgz", @@ -3045,6 +3470,11 @@ "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", "dev": true }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "@types/marked": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.4.2.tgz", @@ -8230,6 +8660,11 @@ } } }, + "dom-storage": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/dom-storage/-/dom-storage-2.1.0.tgz", + "integrity": "sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==" + }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", @@ -8408,7 +8843,6 @@ "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, "requires": { "iconv-lite": "~0.4.13" } @@ -9418,42 +9852,24 @@ } }, "firebase": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-2.4.2.tgz", - "integrity": "sha1-ThEZ7AOWylYdinrL/xYw/qxsCjE=", - "dev": true, - "requires": { - "faye-websocket": ">=0.6.0" - }, - "dependencies": { - "faye-websocket": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz", - "integrity": "sha1-SCpQWw3wrmJrlphm0710DNuWLoM=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - }, - "dependencies": { - "websocket-driver": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.5.2.tgz", - "integrity": "sha1-jHyF2gcTtAYFVrTXHAF3XuEmnrk=", - "dev": true, - "requires": { - "websocket-extensions": ">=0.1.1" - }, - "dependencies": { - "websocket-extensions": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", - "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=", - "dev": true - } - } - } - } - } + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-7.14.5.tgz", + "integrity": "sha512-1vrC1UZIVhaT7owaElQoEseP81xqRt6tHQmxRJRojn0yI3JNXrdWCFsD+26xA1eQQCwodJuMsYJLzQSScgjHuQ==", + "requires": { + "@firebase/analytics": "0.3.5", + "@firebase/app": "0.6.4", + "@firebase/app-types": "0.6.1", + "@firebase/auth": "0.14.6", + "@firebase/database": "0.6.3", + "@firebase/firestore": "1.14.5", + "@firebase/functions": "0.4.44", + "@firebase/installations": "0.4.10", + "@firebase/messaging": "0.6.16", + "@firebase/performance": "0.3.4", + "@firebase/polyfill": "0.3.36", + "@firebase/remote-config": "0.1.21", + "@firebase/storage": "0.3.34", + "@firebase/util": "0.2.47" } }, "firebase-tools": { @@ -9538,6 +9954,45 @@ "object-assign": "^4.1.0" } }, + "firebase": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-2.4.2.tgz", + "integrity": "sha1-ThEZ7AOWylYdinrL/xYw/qxsCjE=", + "dev": true, + "requires": { + "faye-websocket": ">=0.6.0" + }, + "dependencies": { + "faye-websocket": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz", + "integrity": "sha1-SCpQWw3wrmJrlphm0710DNuWLoM=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + }, + "dependencies": { + "websocket-driver": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.5.2.tgz", + "integrity": "sha1-jHyF2gcTtAYFVrTXHAF3XuEmnrk=", + "dev": true, + "requires": { + "websocket-extensions": ">=0.1.1" + }, + "dependencies": { + "websocket-extensions": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=", + "dev": true + } + } + } + } + } + } + }, "fs-extra": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.23.1.tgz", @@ -12476,8 +12931,7 @@ "http-parser-js": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", - "dev": true + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { "version": "1.17.0", @@ -12614,11 +13068,15 @@ "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, + "idb": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/idb/-/idb-3.0.2.tgz", + "integrity": "sha512-+FLa/0sTXqyux0o6C+i2lOR0VoS60LU/jzUo5xjfY6+7sEEgy4Gz1O7yFBXvjd7N0NyIGWIRg8DcQSLEG+VSPw==" + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", @@ -13474,6 +13932,26 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + }, + "dependencies": { + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + } + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -14735,6 +15213,11 @@ "lodash._objecttypes": "~2.4.1" } }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -14953,6 +15436,11 @@ "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -18385,6 +18873,11 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promise-polyfill": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz", + "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==" + }, "promise-retry": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", @@ -18459,6 +18952,33 @@ } } }, + "protobufjs": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.9.0.tgz", + "integrity": "sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.9.tgz", + "integrity": "sha512-EPZBIGed5gNnfWCiwEIwTE2Jdg4813odnG8iNPMQGrqVxrI+wL68SPtPeCX+ZxGBaA6pKAVc6jaKgP/Q0QzfdQ==" + } + } + }, "protochain": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/protochain/-/protochain-1.0.5.tgz", @@ -24576,7 +25096,6 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", - "dev": true, "requires": { "http-parser-js": ">=0.4.0 <0.4.11", "safe-buffer": ">=5.1.0", @@ -24586,8 +25105,12 @@ "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", - "dev": true + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, "when": { "version": "3.6.4", @@ -24815,6 +25338,11 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, "xmlhttprequest-ssl": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", diff --git a/package.json b/package.json index 33e6198de2..079a637d90 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "@angular/common": "^9.0.4", "@angular/compiler": "^9.0.4", "@angular/core": "^9.0.4", + "@angular/fire": "^6.0.0", "@angular/forms": "^9.0.4", "@angular/localize": "^9.0.4", "@angular/platform-browser": "^9.0.4", @@ -101,6 +102,7 @@ "date-fns": "2", "docsearch.js": "^2.5.2", "eva-icons": "^1.1.2", + "firebase": "^7.14.5", "gulp-bump": "2.7.0", "highlight.js": "9.12.0", "intersection-observer": "0.7.0", diff --git a/scripts/gulp/tasks/build/bundle/rollup-config.ts b/scripts/gulp/tasks/build/bundle/rollup-config.ts index 155ee45c11..24914654e2 100644 --- a/scripts/gulp/tasks/build/bundle/rollup-config.ts +++ b/scripts/gulp/tasks/build/bundle/rollup-config.ts @@ -25,6 +25,8 @@ const ROLLUP_GLOBALS = { '@angular/cdk/table': 'ng.cdk.table', '@angular/cdk/bidi': 'ng.cdk.bidi', '@angular/cdk/keycodes': 'ng.cdk.keycodes', + '@angular/fire': 'ng.fire', + '@angular/fire/auth': 'ng.fire.auth', // RxJS dependencies @@ -33,6 +35,9 @@ const ROLLUP_GLOBALS = { // 3rd party dependencies 'intersection-observer': 'intersection-observer', + 'firebase': 'firebase', + 'firebase/app': 'firebase.app', + 'firebase/auth': 'firebase.auth', // date libs for date service 'moment': 'moment', @@ -47,6 +52,7 @@ const ROLLUP_GLOBALS = { '@nebular/moment': 'nb.moment', '@nebular/date-fns': 'nb.date-fns', '@nebular/eva-icons': 'nb.eva-icons', + '@nebular/firebase-auth': 'nb.firebase-auth', 'eva-icons': 'eva-icons', }; diff --git a/scripts/gulp/tasks/change-prefix.ts b/scripts/gulp/tasks/change-prefix.ts index d0277119bf..77b9993e53 100644 --- a/scripts/gulp/tasks/change-prefix.ts +++ b/scripts/gulp/tasks/change-prefix.ts @@ -8,7 +8,7 @@ import { capitalize, dasherize } from '@angular-devkit/core/src/utils/strings'; import { BUILD_DIR } from './config'; -type NebularPackage = 'auth' | 'bootstrap' | 'dateFns' | 'evaIcons' | 'moment' | 'theme' | 'security'; +type NebularPackage = 'auth' | 'bootstrap' | 'dateFns' | 'evaIcons' | 'moment' | 'theme' | 'security' | 'firebase-auth'; interface PackagePrefix { prefix: string; @@ -26,7 +26,16 @@ interface StringReplacement { const ROLLUP_CONFIG_DIR = './scripts/gulp/tasks/bundle'; const ROLLUP_CONFIG_PATH = `${ROLLUP_CONFIG_DIR}/rollup-config.ts`; -const NEBULAR_PACKAGES: NebularPackage[] = ['auth', 'bootstrap', 'dateFns', 'evaIcons', 'moment', 'theme', 'security']; +const NEBULAR_PACKAGES: NebularPackage[] = [ + 'auth', + 'bootstrap', + 'dateFns', + 'evaIcons', + 'moment', + 'theme', + 'security', + 'firebase-auth', +]; /** * Reads package prefix and all package names passed as command line arguments. diff --git a/scripts/gulp/tasks/config.ts b/scripts/gulp/tasks/config.ts index 70e670d756..a27914c898 100644 --- a/scripts/gulp/tasks/config.ts +++ b/scripts/gulp/tasks/config.ts @@ -12,4 +12,5 @@ export const JS_PACKAGES = [ 'moment', 'security', 'theme', + 'firebase-auth', ]; diff --git a/src/app/playground-components.ts b/src/app/playground-components.ts index 039204222f..a857d146e7 100644 --- a/src/app/playground-components.ts +++ b/src/app/playground-components.ts @@ -1797,6 +1797,53 @@ export const PLAYGROUND_COMPONENTS: ComponentLink[] = [ }, ], }, + { + path: 'firebase', + children: [ + { + path: 'login', + link: '/firebase/login', + component: 'NbLoginComponent', + name: 'Nb Login', + }, + { + path: 'register', + link: '/firebase/register', + component: 'NbRegisterComponent', + name: 'Nb Register', + }, + { + path: 'logout', + link: '/firebase/logout', + component: 'NbLogoutComponent', + name: 'Nb Logout', + }, + { + path: 'request-password', + link: '/firebase/request-password', + component: 'NbRequestPasswordComponent', + name: 'Nb Request Password', + }, + { + path: 'reset-password', + link: '/firebase/reset-password', + component: 'NbResetPasswordComponent', + name: 'Nb Reset Password', + }, + { + path: 'password-showcase', + link: '/firebase/password-showcase', + component: 'PasswordAuthShowcaseComponent', + name: 'Password Auth Showcase', + }, + { + path: 'social-auth-showcase', + link: '/firebase/social-auth-showcase', + component: 'IdentityProvidersAuthShowcaseComponent', + name: 'Identity Providers Auth Showcase', + }, + ], + }, { path: 'smart-home', children: [ diff --git a/src/framework/firebase-auth/LICENSE.txt b/src/framework/firebase-auth/LICENSE.txt new file mode 100644 index 0000000000..031c83cb11 --- /dev/null +++ b/src/framework/firebase-auth/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2017 Akveo. + +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. + diff --git a/src/framework/firebase-auth/README.md b/src/framework/firebase-auth/README.md new file mode 100644 index 0000000000..6cb1e27bed --- /dev/null +++ b/src/framework/firebase-auth/README.md @@ -0,0 +1 @@ +### @nebular/firebase-auth module, more details https://akveo.github.io/nebular/ diff --git a/src/framework/firebase-auth/firebase-auth.module.ts b/src/framework/firebase-auth/firebase-auth.module.ts new file mode 100644 index 0000000000..910d78c318 --- /dev/null +++ b/src/framework/firebase-auth/firebase-auth.module.ts @@ -0,0 +1,24 @@ +/* + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + + +import { NgModule } from '@angular/core'; + +import { NbFirebasePasswordStrategy } from './strategies/password/firebase-password.strategy'; +import { NbFirebaseGoogleStrategy } from './strategies/google/firebase-google.strategy'; +import { NbFirebaseFacebookStrategy } from './strategies/facebook/firebase-facebook.strategy'; +import { NbFirebaseTwitteStrategy } from './strategies/twitter/firebase-twitter.strategy'; + + +@NgModule({ + providers: [ + NbFirebasePasswordStrategy, + NbFirebaseGoogleStrategy, + NbFirebaseFacebookStrategy, + NbFirebaseTwitteStrategy, + ], +}) +export class NbFirebaseAuthModule { } diff --git a/src/framework/firebase-auth/package.json b/src/framework/firebase-auth/package.json new file mode 100644 index 0000000000..9f332b6723 --- /dev/null +++ b/src/framework/firebase-auth/package.json @@ -0,0 +1,35 @@ +{ + "name": "@nebular/firebase-auth", + "version": "5.0.0", + "description": "@nebular/firebase-auth", + "author": "akveo", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/akveo/nebular.git" + }, + "bugs": { + "url": "https://github.com/akveo/nebular/issues" + }, + "homepage": "https://github.com/akveo/nebular#readme", + "keywords": [ + "angular", + "typescript", + "ng2-admin", + "ngx-admin", + "theme", + "auth", + "login", + "register", + "nebular", + "firebase" + ], + "peerDependencies": { + "@angular/core": "^9.0.0", + "@nebular/auth": "^5.0.0", + "rxjs": "^6.5.1", + "firebase": "^7.14.5", + "@angular/fire": "^6.0.0" + }, + "sideEffects": false +} diff --git a/src/framework/firebase-auth/public_api.ts b/src/framework/firebase-auth/public_api.ts new file mode 100644 index 0000000000..205dea594d --- /dev/null +++ b/src/framework/firebase-auth/public_api.ts @@ -0,0 +1,15 @@ +/* + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + + +export * from './strategies/base/firebase-base.strategy'; +export * from './strategies/password/firebase-password.strategy'; +export * from './strategies/password/firebase-password-strategy.options'; +export * from './strategies/base/firebase-identity-provider-strategy.options'; +export * from './strategies/google/firebase-google.strategy'; +export * from './strategies/facebook/firebase-facebook.strategy'; +export * from './strategies/twitter/firebase-twitter.strategy'; +export * from './firebase-auth.module'; diff --git a/src/framework/firebase-auth/strategies/base/firebase-base.strategy.ts b/src/framework/firebase-auth/strategies/base/firebase-base.strategy.ts new file mode 100644 index 0000000000..b9340824f4 --- /dev/null +++ b/src/framework/firebase-auth/strategies/base/firebase-base.strategy.ts @@ -0,0 +1,87 @@ +/* + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { Injectable } from '@angular/core'; +import { AngularFireAuth } from '@angular/fire/auth'; +import { Observable, of as observableOf, from } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; +import { NbAuthResult, NbAuthIllegalTokenError, NbAuthStrategy } from '@nebular/auth'; + +import UserCredential = firebase.auth.UserCredential; + + +@Injectable() +export abstract class NbFirebaseBaseStrategy extends NbAuthStrategy { + + constructor(protected afAuth: AngularFireAuth) { + super(); + } + + logout(): Observable { + const module = 'logout'; + return from(this.afAuth.signOut()) + .pipe( + map(() => { + return new NbAuthResult( + true, + null, + this.getOption(`${module}.redirect.success`), + [], + this.getOption(`${module}.defaultMessages`), + ) + }), + catchError((error) => this.processFailure(error, module)), + ); + } + + register(data?: any): Observable { + throw new Error(`'register' is not supported by '${this.constructor.name}', use 'authenticate'.`); + } + + requestPassword(data?: any): Observable { + throw new Error(`'requestPassword' is not supported by '${this.constructor.name}', use 'authenticate'.`); + } + + resetPassword(data: any = {}): Observable { + throw new Error(`'resetPassword' is not supported by '${this.constructor.name}', use 'authenticate'.`); + } + + refreshToken(data: any = {}): Observable { + throw new Error(`'refreshToken' is not supported by '${this.constructor.name}', use 'authenticate'.`); + } + + protected processFailure(error: any, module: string): Observable { + const errorMessages = []; + + if (error instanceof NbAuthIllegalTokenError) { + errorMessages.push(error.message) + } else { + errorMessages.push(this.getOption('errors.getter')(module, error, this.options)); + } + + return observableOf(new NbAuthResult( + false, + error, + this.getOption(`${module}.redirect.failure`), + errorMessages, + [], + )); + } + + protected processSuccess(res: UserCredential | null, module: string): Observable { + return this.afAuth.idToken + .pipe(map(token => { + return new NbAuthResult( + true, + res, + this.getOption(`${module}.redirect.success`), + [], + this.getOption('messages.getter')(module, res, this.options), + this.createToken(token), + ); + })); + } +} diff --git a/src/framework/firebase-auth/strategies/base/firebase-identity-provider-strategy.options.ts b/src/framework/firebase-auth/strategies/base/firebase-identity-provider-strategy.options.ts new file mode 100644 index 0000000000..d72235981e --- /dev/null +++ b/src/framework/firebase-auth/strategies/base/firebase-identity-provider-strategy.options.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { + NbPasswordStrategyMessage, + NbPasswordStrategyModule, + NbAuthJWTToken, + NbAuthStrategyOptions, +} from '@nebular/auth'; + +export class NbFirebaseIdentityProviderStrategyOptions extends NbAuthStrategyOptions { + token? = { + class: NbAuthJWTToken, + }; + logout?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully logged out.'], + }; + authenticate?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully authenticated.'], + }; + errors?: NbPasswordStrategyMessage = { + key: 'message', + getter: (module: string, res, options: NbFirebaseIdentityProviderStrategyOptions) => options[module].defaultErrors, + }; + messages?: NbPasswordStrategyMessage = { + key: 'message', + getter: (module: string, res, options: NbFirebaseIdentityProviderStrategyOptions) => { + return options[module].defaultMessages; + }, + }; + scopes?: string[] = []; + customParameters?: { [key: string]: string } = {}; +}; diff --git a/src/framework/firebase-auth/strategies/facebook/firebase-facebook.strategy.ts b/src/framework/firebase-auth/strategies/facebook/firebase-facebook.strategy.ts new file mode 100644 index 0000000000..886c34a734 --- /dev/null +++ b/src/framework/firebase-auth/strategies/facebook/firebase-facebook.strategy.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + + +import { Injectable } from '@angular/core'; +import { NbAuthResult, NbAuthStrategyClass, NbAuthStrategyOptions } from '@nebular/auth'; +import { from, Observable } from 'rxjs'; +import { catchError, switchMap } from 'rxjs/operators'; + +import { NbFirebaseBaseStrategy } from '../base/firebase-base.strategy'; +import { NbFirebaseIdentityProviderStrategyOptions } from '../base/firebase-identity-provider-strategy.options'; + +import * as firebase from 'firebase/app'; +import 'firebase/auth'; + + +@Injectable() +export class NbFirebaseFacebookStrategy extends NbFirebaseBaseStrategy { + + protected defaultOptions: NbFirebaseIdentityProviderStrategyOptions = new NbFirebaseIdentityProviderStrategyOptions(); + + static setup(options: NbFirebaseIdentityProviderStrategyOptions): [NbAuthStrategyClass, NbAuthStrategyOptions] { + return [NbFirebaseFacebookStrategy, options]; + } + + authenticate(data?: any): Observable { + const module = 'authenticate'; + const provider = new firebase.auth.FacebookAuthProvider(); + const scopes = this.getOption('scopes'); + scopes.forEach((scope) => provider.addScope(scope)); + provider.setCustomParameters(this.getOption('customParameters')); + + return from(this.afAuth.signInWithPopup(provider)) + .pipe( + switchMap((res) => this.processSuccess(res, module)), + catchError(error => this.processFailure(error, module)), + ); + } +} diff --git a/src/framework/firebase-auth/strategies/google/firebase-google.strategy.ts b/src/framework/firebase-auth/strategies/google/firebase-google.strategy.ts new file mode 100644 index 0000000000..d7c5b72f1a --- /dev/null +++ b/src/framework/firebase-auth/strategies/google/firebase-google.strategy.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { Injectable } from '@angular/core'; +import { from, Observable } from 'rxjs'; +import { catchError, switchMap } from 'rxjs/operators'; +import { NbAuthStrategyClass, NbAuthResult, NbAuthStrategyOptions } from '@nebular/auth'; + +import { NbFirebaseBaseStrategy } from '../base/firebase-base.strategy'; +import { NbFirebaseIdentityProviderStrategyOptions } from '../base/firebase-identity-provider-strategy.options'; + +import * as firebase from 'firebase/app'; +import 'firebase/auth'; + +@Injectable() +export class NbFirebaseGoogleStrategy extends NbFirebaseBaseStrategy { + + protected defaultOptions: NbFirebaseIdentityProviderStrategyOptions = new NbFirebaseIdentityProviderStrategyOptions(); + + static setup(options: NbFirebaseIdentityProviderStrategyOptions): [NbAuthStrategyClass, NbAuthStrategyOptions] { + return [NbFirebaseGoogleStrategy, options]; + } + + authenticate(data?: any): Observable { + const module = 'authenticate'; + const provider = new firebase.auth.GoogleAuthProvider(); + const scopes = this.getOption('scopes'); + scopes.forEach((scope) => provider.addScope(scope)); + provider.setCustomParameters(this.getOption('customParameters')); + + return from(this.afAuth.signInWithPopup(provider)) + .pipe( + switchMap((res) => this.processSuccess(res, module)), + catchError(error => this.processFailure(error, module)), + ); + } +} diff --git a/src/framework/firebase-auth/strategies/password/firebase-password-strategy.options.ts b/src/framework/firebase-auth/strategies/password/firebase-password-strategy.options.ts new file mode 100644 index 0000000000..553ca1446c --- /dev/null +++ b/src/framework/firebase-auth/strategies/password/firebase-password-strategy.options.ts @@ -0,0 +1,86 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { + getDeepFromObject, + NbAuthJWTToken, + NbAuthStrategyOptions, + NbPasswordStrategyMessage, + NbPasswordStrategyModule, +} from '@nebular/auth'; + +export class NbFirebasePasswordStrategyOptions extends NbAuthStrategyOptions { + token? = { + class: NbAuthJWTToken, + }; + register?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully registered.'], + }; + login?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Login/Email combination is not correct, please try again.'], + defaultMessages: ['You have been successfully logged in.'], + }; + logout?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['You have been successfully logged out.'], + }; + refreshToken?: boolean | NbPasswordStrategyModule = { + redirect: { + success: null, + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['Your token has been successfully refreshed.'], + }; + requestPassword?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['Reset password instructions have been sent to your email.'], + }; + resetPassword?: boolean | NbPasswordStrategyModule = { + redirect: { + success: '/', + failure: null, + }, + defaultErrors: ['Something went wrong, please try again.'], + defaultMessages: ['Your password has been successfully changed.'], + }; + errors?: NbPasswordStrategyMessage = { + key: 'message', + getter: (module: string, res, options: NbFirebasePasswordStrategyOptions) => getDeepFromObject( + res, + options.errors.key, + options[module].defaultErrors, + ), + }; + messages?: NbPasswordStrategyMessage = { + key: 'messages', + getter: (module: string, res, options: NbFirebasePasswordStrategyOptions) => getDeepFromObject( + res.body, + options.messages.key, + options[module].defaultMessages, + ), + }; +} + +// tslint:disable-next-line:max-line-length +export const firebasePasswordStrategyOptions: NbFirebasePasswordStrategyOptions = new NbFirebasePasswordStrategyOptions(); diff --git a/src/framework/firebase-auth/strategies/password/firebase-password.strategy.ts b/src/framework/firebase-auth/strategies/password/firebase-password.strategy.ts new file mode 100644 index 0000000000..48c6570465 --- /dev/null +++ b/src/framework/firebase-auth/strategies/password/firebase-password.strategy.ts @@ -0,0 +1,133 @@ +/* + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { Injectable } from '@angular/core'; +import { User } from 'firebase'; +import { Observable, of as observableOf, from } from 'rxjs'; +import { catchError, map, switchMap, take } from 'rxjs/operators'; +import { NbAuthStrategyOptions, NbAuthStrategyClass, NbAuthResult } from '@nebular/auth'; + +import { NbFirebaseBaseStrategy } from '../base/firebase-base.strategy'; +import { + firebasePasswordStrategyOptions, + NbFirebasePasswordStrategyOptions, +} from './firebase-password-strategy.options'; + + +@Injectable() +export class NbFirebasePasswordStrategy extends NbFirebaseBaseStrategy { + + protected defaultOptions: NbFirebasePasswordStrategyOptions = firebasePasswordStrategyOptions; + + static setup(options: NbFirebasePasswordStrategyOptions): [NbAuthStrategyClass, NbAuthStrategyOptions] { + return [NbFirebasePasswordStrategy, options]; + } + + authenticate({ email, password }: any): Observable { + const module = 'login'; + return from(this.afAuth.signInWithEmailAndPassword(email, password)) + .pipe( + switchMap((res) => this.processSuccess(res, module)), + catchError((error) => this.processFailure(error, module)), + ); + } + + refreshToken(data?: any): Observable { + const module = 'refreshToken'; + return this.afAuth.authState + .pipe( + take(1), + switchMap(user => { + if (user == null) { + return observableOf(new NbAuthResult( + false, + null, + this.getOption(`${module}.redirect.failure`), + ['There is no logged in user so refresh of id token isn\'t possible'], + )); + } + return this.refreshIdToken(user, module); + }), + ); + } + + register({ email, password }: any): Observable { + const module = 'register'; + return from(this.afAuth.createUserWithEmailAndPassword(email, password)) + .pipe( + switchMap((res) => this.processSuccess(res, module)), + catchError((error) => this.processFailure(error, module)), + ); + } + + requestPassword({ email }: any): Observable { + const module = 'requestPassword'; + return from(this.afAuth.sendPasswordResetEmail(email)) + .pipe( + map(() => { + return new NbAuthResult( + true, + null, + this.getOption(`${module}.redirect.success`), + [], + this.getOption(`${module}.defaultMessages`), + ); + }), + catchError((error) => this.processFailure(error, module)), + ); + } + + resetPassword({ code, password }): Observable { + const module = 'resetPassword'; + return from(this.afAuth.confirmPasswordReset(code, password)) + .pipe( + map(() => { + return new NbAuthResult( + true, + null, + this.getOption(`${module}.redirect.success`), + [], + this.getOption(`${module}.defaultMessages`), + ); + }), + catchError((error) => this.processFailure(error, module)), + ); + } + + protected updatePassword(user, password, module) { + return from(user.updatePassword(password)) + .pipe( + map(token => { + return new NbAuthResult( + true, + null, + this.getOption(`${module}.redirect.success`), + [], + this.getOption(`${module}.defaultMessages`), + this.createToken(token), + ); + }), + catchError(error => this.processFailure(error, module)), + ); + } + + protected refreshIdToken(user: User, module): Observable { + return from(user.getIdToken(true)) + .pipe( + map(token => { + return new NbAuthResult( + true, + null, + this.getOption(`${module}.redirect.success`), + [], + this.getOption(`${module}.defaultMessages`), + this.createToken(token), + ); + }), + catchError(error => this.processFailure(error, module)), + ); + } +} diff --git a/src/framework/firebase-auth/strategies/twitter/firebase-twitter.strategy.ts b/src/framework/firebase-auth/strategies/twitter/firebase-twitter.strategy.ts new file mode 100644 index 0000000000..365c9c501b --- /dev/null +++ b/src/framework/firebase-auth/strategies/twitter/firebase-twitter.strategy.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { Injectable } from '@angular/core'; +import { Observable, from } from 'rxjs'; +import { catchError, switchMap } from 'rxjs/operators'; +import { NbAuthStrategyClass, NbAuthResult, NbAuthStrategyOptions } from '@nebular/auth'; + +import { NbFirebaseBaseStrategy } from '../base/firebase-base.strategy'; +import { NbFirebaseIdentityProviderStrategyOptions } from '../base/firebase-identity-provider-strategy.options'; + +import * as firebase from 'firebase/app'; +import 'firebase/auth'; + +@Injectable() +export class NbFirebaseTwitteStrategy extends NbFirebaseBaseStrategy { + + protected defaultOptions: NbFirebaseIdentityProviderStrategyOptions = new NbFirebaseIdentityProviderStrategyOptions(); + + static setup(options: NbFirebaseIdentityProviderStrategyOptions): [NbAuthStrategyClass, NbAuthStrategyOptions] { + return [NbFirebaseTwitteStrategy, options]; + } + + authenticate(data?: any): Observable { + const module = 'authenticate'; + const provider = new firebase.auth.TwitterAuthProvider(); + provider.setCustomParameters(this.getOption('customParameters')); + + return from(this.afAuth.signInWithPopup(provider)) + .pipe( + switchMap((res) => this.processSuccess(res, module)), + catchError(error => this.processFailure(error, module)), + ); + } +} diff --git a/src/playground/without-layout/firebase/firebase-api.service.ts b/src/playground/without-layout/firebase/firebase-api.service.ts new file mode 100644 index 0000000000..02a8adfa5c --- /dev/null +++ b/src/playground/without-layout/firebase/firebase-api.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@angular/core'; +import { AngularFireDatabase } from '@angular/fire/database'; + +@Injectable() +export class FirebaseAPIService { + + constructor(private db: AngularFireDatabase) { } + + getGreeting() { + return this.db.object('/greeting/').valueChanges(); + } +} diff --git a/src/playground/without-layout/firebase/firebase-playground.component.ts b/src/playground/without-layout/firebase/firebase-playground.component.ts new file mode 100644 index 0000000000..cfd2315915 --- /dev/null +++ b/src/playground/without-layout/firebase/firebase-playground.component.ts @@ -0,0 +1,16 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'nb-firebase-playground', + template: ` + + `, +}) +export class FirebasePlaygroundComponent { +} diff --git a/src/playground/without-layout/firebase/firebase-routing.module.ts b/src/playground/without-layout/firebase/firebase-routing.module.ts new file mode 100644 index 0000000000..6db5319b04 --- /dev/null +++ b/src/playground/without-layout/firebase/firebase-routing.module.ts @@ -0,0 +1,79 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { + NbAuthComponent, + NbLoginComponent, + NbLogoutComponent, + NbRegisterComponent, + NbRequestPasswordComponent, + NbResetPasswordComponent, +} from '@nebular/auth'; + +import { FirebasePlaygroundComponent } from './firebase-playground.component'; +import { PasswordAuthShowcaseComponent } from './password-auth-showcase/password-auth-showcase.component'; +import { + IdentityProvidersAuthShowcaseComponent, +} from './identity-proders-auth-showcase/identity-providers-auth-showcase.component'; + + +export const routes: Routes = [ + { + path: '', + component: FirebasePlaygroundComponent, + children: [ + { + path: '', + component: NbAuthComponent, + children: [ + { + path: '', + redirectTo: 'login', + pathMatch: 'full', + }, + { + path: 'login', + component: NbLoginComponent, + }, + { + path: 'register', + component: NbRegisterComponent, + }, + { + path: 'logout', + component: NbLogoutComponent, + }, + { + path: 'request-password', + component: NbRequestPasswordComponent, + }, + { + path: 'reset-password', + component: NbResetPasswordComponent, + }, + ], + }, + ], + }, + { + path: 'password-showcase', + component: PasswordAuthShowcaseComponent, + }, + { + path: 'social-auth-showcase', + component: IdentityProvidersAuthShowcaseComponent, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class FirebasePlaygroundRoutingModule { +} diff --git a/src/playground/without-layout/firebase/firebase.module.ts b/src/playground/without-layout/firebase/firebase.module.ts new file mode 100644 index 0000000000..9e24ffae9e --- /dev/null +++ b/src/playground/without-layout/firebase/firebase.module.ts @@ -0,0 +1,117 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { AngularFireModule } from '@angular/fire'; +import { AngularFireAuthModule } from '@angular/fire/auth'; +import { AngularFireDatabaseModule } from '@angular/fire/database'; +import { NbAuthModule } from '@nebular/auth'; +import { NbFirebaseAuthModule, NbFirebasePasswordStrategy, NbFirebaseGoogleStrategy } from '@nebular/firebase-auth'; + +import { FirebaseAPIService } from './firebase-api.service'; +import { FirebasePlaygroundComponent } from './firebase-playground.component'; +import { FirebasePlaygroundRoutingModule } from './firebase-routing.module'; +import { + IdentityProvidersAuthShowcaseComponent, +} from './identity-proders-auth-showcase/identity-providers-auth-showcase.component'; +import { PasswordAuthShowcaseComponent } from './password-auth-showcase/password-auth-showcase.component'; + +@NgModule({ + imports: [ + CommonModule, + AngularFireModule.initializeApp({ + apiKey: 'AIzaSyBEvySH74-sISCTkCC6lXUd3zzYj26GjRk', + authDomain: 'auth-sample-f48f1.firebaseapp.com', + databaseURL: 'https://auth-sample-f48f1.firebaseio.com', + projectId: 'auth-sample-f48f1', + storageBucket: 'auth-sample-f48f1.appspot.com', + messagingSenderId: '246754092661', + appId: '1:246754092661:web:c2606b9ecdbed579673a3c', + }), + AngularFireAuthModule, + AngularFireDatabaseModule, + FirebasePlaygroundRoutingModule, + NbFirebaseAuthModule, + NbAuthModule.forRoot({ + forms: { + login: { + strategy: 'password', + rememberMe: true, + socialLinks: [], + }, + register: { + strategy: 'password', + terms: true, + socialLinks: [], + }, + logout: { + strategy: 'password', + }, + requestPassword: { + strategy: 'password', + socialLinks: [], + }, + resetPassword: { + strategy: 'password', + socialLinks: [], + }, + validation: { + password: { + required: true, + minLength: 6, + maxLength: 50, + }, + email: { + required: true, + }, + fullName: { + required: false, + minLength: 4, + maxLength: 50, + }, + }, + }, + strategies: [ + NbFirebasePasswordStrategy.setup({ + name: 'password', + login: { + redirect: { + success: 'example/firebase/password-showcase', + }, + }, + register: { + redirect: { + success: 'example/firebase/password-showcase', + }, + }, + logout: { + redirect: { + success: 'example/firebase/login', + }, + }, + requestPassword: { + redirect: { + success: 'example/firebase/login', + }, + }, + resetPassword: { + redirect: { + success: 'example/firebase/login', + }, + }, + }), + NbFirebaseGoogleStrategy.setup({ + name: 'google', + }), + ], + }), + ], + declarations: [ + FirebasePlaygroundComponent, + PasswordAuthShowcaseComponent, + IdentityProvidersAuthShowcaseComponent, + ], + providers: [ + FirebaseAPIService, + ], +}) +export class FirebasePlaygroundModule { +} diff --git a/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.html b/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.html new file mode 100644 index 0000000000..bbb3fb6e2a --- /dev/null +++ b/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.html @@ -0,0 +1,25 @@ +
Authenticated: {{ isAuthenticated$ | async }}
+ +
+ Current User Token: +
 {{ userToken$ | async | json }} 
+
+ +
+ Data from backend +
{{ data$ | async | json }}
+
+ + + + + + diff --git a/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.scss b/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.ts b/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.ts new file mode 100644 index 0000000000..78681a8db9 --- /dev/null +++ b/src/playground/without-layout/firebase/identity-proders-auth-showcase/identity-providers-auth-showcase.component.ts @@ -0,0 +1,47 @@ +import { Component } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { catchError, share, take } from 'rxjs/operators'; +import { NbAuthResult, NbAuthService, NbAuthToken } from '@nebular/auth'; + +import { FirebaseAPIService } from '../firebase-api.service'; + +@Component({ + selector: 'app-google-auth-showcase', + templateUrl: './identity-providers-auth-showcase.component.html', + styleUrls: ['./identity-providers-auth-showcase.component.scss'], +}) +export class IdentityProvidersAuthShowcaseComponent { + + userToken$: Observable; + isAuthenticated$: Observable; + data$: Observable; + + constructor( + private firebaseApi: FirebaseAPIService, + private authService: NbAuthService, + ) { + this.userToken$ = this.authService.onTokenChange(); + this.isAuthenticated$ = this.authService.onAuthenticationChange(); + } + + logout() { + this.authService.logout('google') + .pipe(take(1)) + .subscribe((authResult: NbAuthResult) => {}); + } + + loginWithGoogle() { + this.authService.authenticate('google') + .pipe(take(1)) + .subscribe((authResult: NbAuthResult) => {}); + } + + getData() { + this.data$ = this.firebaseApi.getGreeting() + .pipe( + take(1), + catchError((error) => of(error)), + share(), + ); + } +} diff --git a/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.html b/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.html new file mode 100644 index 0000000000..726740315b --- /dev/null +++ b/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.html @@ -0,0 +1,27 @@ +
Authenticated: {{ isAuthenticated$ | async }}
+ +
+ Current User Token: +
 {{ userToken$ | async | json }} 
+
+ +
+ Data from backend +
{{ data$ | async | json }}
+
+ + + + + + + + diff --git a/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.scss b/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.ts b/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.ts new file mode 100644 index 0000000000..50d680e257 --- /dev/null +++ b/src/playground/without-layout/firebase/password-auth-showcase/password-auth-showcase.component.ts @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Observable, of } from 'rxjs'; +import { catchError, share, take } from 'rxjs/operators'; +import { NbAuthService, NbAuthToken } from '@nebular/auth'; + +import { FirebaseAPIService } from '../firebase-api.service'; + +@Component({ + selector: 'nb-password-auth-showcase', + templateUrl: './password-auth-showcase.component.html', + styleUrls: ['./password-auth-showcase.component.scss'], +}) +export class PasswordAuthShowcaseComponent { + + userToken$: Observable; + isAuthenticated$: Observable; + data$: Observable; + + constructor( + private authService: NbAuthService, + private router: Router, + private firebaseApi: FirebaseAPIService, + private route: ActivatedRoute, + ) { + this.userToken$ = this.authService.onTokenChange(); + this.isAuthenticated$ = this.authService.isAuthenticated(); + } + + logout() { + this.router.navigate(['../logout'], { relativeTo: this.route }); + } + + login() { + this.router.navigate(['../login'], { relativeTo: this.route }); + } + + resetPassword() { + this.router.navigate(['../reset-password'], { relativeTo: this.route }); + } + + getData() { + this.data$ = this.firebaseApi.getGreeting() + .pipe( + take(1), + catchError((error) => of(error)), + share(), + ); + } +} diff --git a/src/playground/without-layout/without-layout-routing.module.ts b/src/playground/without-layout/without-layout-routing.module.ts index a45d2a9ac3..43d35da7c3 100644 --- a/src/playground/without-layout/without-layout-routing.module.ts +++ b/src/playground/without-layout/without-layout-routing.module.ts @@ -49,6 +49,10 @@ const routes: Route[] = [ path: 'auth', loadChildren: () => import('./auth/auth.module').then(m => m.AuthPlaygroundModule), }, + { + path: 'firebase', + loadChildren: () => import('./firebase/firebase.module').then(m => m.FirebasePlaygroundModule), + }, { path: 'smart-home', loadChildren: () => import('./smart-home/app.module').then(m => m.AppModule), diff --git a/tsconfig.publish.json b/tsconfig.publish.json index a7c49fbbbb..50cb76ee20 100644 --- a/tsconfig.publish.json +++ b/tsconfig.publish.json @@ -18,7 +18,8 @@ "importHelpers": true, "baseUrl": ".", "paths": { - "@nebular/theme": ["./src/.lib/theme"] + "@nebular/theme": ["./src/.lib/theme"], + "@nebular/auth": ["./src/.lib/auth"] }, "skipLibCheck": true, "typeRoots": [