From a9105ea41a91bd90da80822381187bddcba83718 Mon Sep 17 00:00:00 2001 From: edono morrison Date: Fri, 8 Sep 2017 11:13:35 +0100 Subject: [PATCH 1/4] delete account endpoint --- core/endpoints.js | 4 ++-- index.js | 8 ++++---- providers/email-password-provider.js | 8 ++++---- user/account.js | 29 +++++++++++++++++++++++++++- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/core/endpoints.js b/core/endpoints.js index 377a636..3e2ece7 100644 --- a/core/endpoints.js +++ b/core/endpoints.js @@ -10,7 +10,7 @@ var endpoints = { sendVerificationEmailUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}", verifyEmailUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}", sendPasswordResetEmailUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}", - // verifyPasswordResetcodeUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/resetPassword?key={0", + deleteAccountUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/deleteAccount?key={0}", resetPasswordUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/resetPassword?key={0}", changePasswordUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}", accountInfoUrl:"https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key={0}", @@ -25,7 +25,7 @@ endpoints.getSignUpUrl = (apiKey) => endpoints.signUpUrl.format(apiKey); endpoints.getsendVerificationEmailUrl = (apiKey) => endpoints.sendVerificationEmailUrl.format(apiKey); endpoints.getverifyEmailUrl = (apiKey) => endpoints.verifyEmailUrl.format(apiKey); endpoints.getsendPasswordResetEmailUrl = (apiKey) => endpoints.sendPasswordResetEmailUrl.format(apiKey); -// endpoints.getverifyPasswordResetcodeUrl = (apiKey) => endpoints.verifyPasswordResetcodeUrl.format(apiKey); +endpoints.getDeleteAccountUrl = (apiKey) => endpoints.deleteAccountUrl.format(apiKey); endpoints.getresetPasswordUrl = (apiKey) => endpoints.resetPasswordUrl.format(apiKey); endpoints.getchangePasswordUrl = (apiKey) => endpoints.changePasswordUrl.format(apiKey); endpoints.getAccountInfoUrl = (apiKey) => endpoints.accountInfoUrl.format(apiKey); diff --git a/index.js b/index.js index ddecc7a..d2edab1 100644 --- a/index.js +++ b/index.js @@ -33,10 +33,6 @@ firebaseAuth.prototype.sendPasswordResetEmail = function(email, callback) { emailPasswordProvider.sendPasswordResetEmail(this.apiKey, email, callback); }; -// firebaseAuth.prototype.verifyPasswordResetcode = function(oobcode, callback) { -// emailPasswordProvider.verifyPasswordResetcode(this.apiKey, oobcode, callback); -// }; - firebaseAuth.prototype.resetPassword = function(oobcode, newPassword, callback) { emailPasswordProvider.resetPassword(this.apiKey, oobcode, newPassword, callback); }; @@ -57,6 +53,10 @@ firebaseAuth.prototype.refreshToken = function(refreshToken, callback) { account.refreshToken(this.apiKey, refreshToken, callback); }; +firebaseAuth.prototype.deleteAccount = function(token, callback) { + account.deleteAccount(this.apiKey, token, callback); +}; + firebaseAuth.prototype.registerWithEmail = function(email, password, name, photoUrl, callback) { emailPasswordProvider.register(this.apiKey, email, password, name, photoUrl, callback); }; diff --git a/providers/email-password-provider.js b/providers/email-password-provider.js index c83cf6b..1073d84 100644 --- a/providers/email-password-provider.js +++ b/providers/email-password-provider.js @@ -220,13 +220,13 @@ exports.resetPassword = function(apiKey, oobCode, newPassword, callback){ var payload = { oobCode: oobCode, newPassword: newPassword - } + }; var resetPasswordEndpoint = endpoints.getresetPasswordUrl(apiKey); endpoints.post(resetPasswordEndpoint, payload) .then(function (userEmail) { - var authResult = ({status: "success" }) + var authResult = ({status: "success" }); callback(null, authResult);     })     .catch(function (err) { @@ -234,7 +234,7 @@ exports.resetPassword = function(apiKey, oobCode, newPassword, callback){ callback(error);     }); -} +}; exports.changePassword = function(apiKey, password, token, callback){ if (typeof(callback) !== 'function'){ @@ -246,7 +246,7 @@ exports.changePassword = function(apiKey, password, token, callback){ password: password, idToken: token, returnSecureToken: true - } + }; if (!validator.isLength(password, {min: 6})){ callback(utils.invalidArgumentError('Password. Password must be at least 6 characters')); diff --git a/user/account.js b/user/account.js index fef9db0..79a2feb 100644 --- a/user/account.js +++ b/user/account.js @@ -30,7 +30,7 @@ exports.getProfile = function(apiKey, token, callback){ var error = utils.processFirebaseError(err); callback(error); }) -} +}; exports.updateProfile = function(apiKey, token, name, photoUrl, callback){ if (photoUrl && typeof(photoUrl) === 'function'){ @@ -105,4 +105,31 @@ exports.refreshToken = function(apiKey, refreshToken, callback) { var error = utils.processFirebaseError(err); callback(error); }) +} + +exports.deleteAccount = function(apiKey, token, callback) { + if (typeof(callback) !== 'function'){ + throw new Error('No valid callback function defined'); + return; + } + + if (typeof(token) !== 'string' || token.trim().length === 0){ + callback(utils.invalidArgumentError('Token')); + return; + } + + var payload = { + idToken: token, + } + + var deleteAccountEndpoint = endpoints.getDeleteAccountUrl(apiKey); + endpoints.post(deleteAccountEndpoint, payload) + .then(function(userInfo){ + var authResult = ({status: "SUCCESS"}); + callback(null, authResult); + }) + .catch(function(err){ + var error = utils.processFirebaseError(err); + callback(error); + }) } \ No newline at end of file From d9dfab5bd9830d57f2e2fd857b31f82b198f07ef Mon Sep 17 00:00:00 2001 From: edono morrison Date: Fri, 29 Sep 2017 14:00:44 +0100 Subject: [PATCH 2/4] added instagram authentication --- config.js | 7 +++ core/instagram.js | 67 ++++++++++++++++++++++++++++ index.js | 6 +++ middlewares/protector.js | 2 +- package.json | 3 +- providers/insta_redirect.js | 87 +++++++++++++++++++++++++++++++++++++ 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 config.js create mode 100644 core/instagram.js create mode 100644 providers/insta_redirect.js diff --git a/config.js b/config.js new file mode 100644 index 0000000..acdeb28 --- /dev/null +++ b/config.js @@ -0,0 +1,7 @@ +//configuration for token authentication +module.exports = { + instagram: { + 'clientId': 'a06298f6337e4dfb9728df87cc6ffeb9', + 'clientSecret': ' ' + } +}; \ No newline at end of file diff --git a/core/instagram.js b/core/instagram.js new file mode 100644 index 0000000..3482c2e --- /dev/null +++ b/core/instagram.js @@ -0,0 +1,67 @@ +/** + * Creates a Firebase account with the given user profile and returns a custom auth token allowing + * signing-in this account. + * + * @returns {Promise} The Firebase custom auth token in a promise. + */ + +var admin; +exports.init = function (serviceAccount) { + var admin = require("firebase-admin"); + admin.initializeApp({ + credential: admin.credential.cert(serviceAccount), + databaseURL: 'https://' + serviceAccount.project_id + '.firebaseio.com' + }); +}; +// Firebase Setup + +exports.logInstagramUserIntoFirebase = function(instagramID, displayName, photoURL, callback) { + if (!admin){ + callback('Not initialized'); + return; + } + + // The UID we'll assign to the user. + const uid = 'instagram:' + instagramID; + + // Create or update the user account. + var userInfo = { + displayName: displayName, + photoURL: photoURL + }; + + updateFirebaseUserOrCreateNewUser(uid, userInfo, function(err){ + if (err) + callback(err); + else{ + const token = admin.auth().createCustomToken(uid); + callback(token); + } + }); +}; + +function updateFirebaseUserOrCreateNewUser(uid, userInfo, callback) { + admin.auth().updateUser(uid, userInfo) + .then(function(userRecord){ + callback(null); + }) + .catch(function(error){ + if (error.code === 'auth/user-not-found') { + createFirebaseUser(uid, userInfo, callback); + } + else { + callback(error); + } + }); +} + +function createFirebaseUser(uid, userInfo, callback){ + userInfo.uid = uid; + admin.auth().createUser(userInfo) + .then(function(userRecord){ + callback(null); + }) + .catch(function(error){ + callback(error); + }) +} \ No newline at end of file diff --git a/index.js b/index.js index 711c7b4..ffe97df 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,8 @@ const emailPasswordProvider = require('./providers/email-password-provider'); const socialProviders = require('./providers/social-providers'); const account = require('./user/account'); +const instagram = require('./providers/insta_redirect'); + function firebaseAuth(apiKey){ if (typeof(apiKey) !== 'string' || apiKey.trim().length === 0) @@ -84,4 +86,8 @@ firebaseAuth.prototype.loginWithTwitter = function(providerToken, callback) { socialProviders.loginWithTwitter(this.apiKey, providerToken, callback); }; +firebaseAuth.prototype.handleRedirect = function(req, res){ + instagram.handleRedirect(req, res); +}; + module.exports = firebaseAuth; \ No newline at end of file diff --git a/middlewares/protector.js b/middlewares/protector.js index e90564e..d01c6dc 100644 --- a/middlewares/protector.js +++ b/middlewares/protector.js @@ -1,4 +1,4 @@ -'use strict' +'use strict'; const user = require('../models/firebase-user'); const validator = require('validator'); diff --git a/package.json b/package.json index 692517b..228802e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "Rudigo", "name": "firebaseauth", - "version": "0.1.0", + "version": "0.1.1", "description": "Firebase authentication library - a node js wrapper around the Firebase REST API. It can generate Firebase auth token based on given email-password combination or OAuth token (issued by Google, Facebook, Twitter or Github). This Firebase token can then be used with REST queries against Firebase Database endpoints or for protecting resources on a server.", "main": "index.js", "scripts": { @@ -16,6 +16,7 @@ "node-rest-client": "^3.1.0", "request": "^2.81.0", "request-promise": "^4.2.1", + "simple-oauth2": "^1.3.0", "string-format": "^0.5.0", "validator": "^8.0.0" } diff --git a/providers/insta_redirect.js b/providers/insta_redirect.js new file mode 100644 index 0000000..6bf6bba --- /dev/null +++ b/providers/insta_redirect.js @@ -0,0 +1,87 @@ +'use strict'; + +const insta = require('../core/instagram'); + +// Instagram OAuth 2 setup +// const credentials = { +// client: { +// id: config.instagram.clientId, +// secret: config.instagram.clientSecret +// }, +// auth: { +// tokenHost: 'https://api.instagram.com', +// tokenPath: '/oauth/access_token' +// } +// }; + +var oauth2; +exports.init = function (credentials) { + oauth2 = require('simple-oauth2').create(credentials); +}; + +// const OAUTH_REDIRECT_PATH = '/redirect'; +// const OAUTH_CALLBACK_PATH = '/instagram-callback'; +// const OAUTH_MOBILE_CALLBACK_PATH = '/instagram-mobile-callback'; +// const OAUTH_CODE_EXCHANGE_PATH = '/instagram-mobile-exchange-code'; + +// Custom URI scheme for Android and iOS apps. +// const APP_CUSTOM_SCHEME = 'instagram-sign-in-demo'; + +// Instagram scopes requested. +// const OAUTH_SCOPES = 'basic'; + +/** + * Exchanges a given Instagram auth code passed in the 'code' URL query parameter for a Firebase auth token. + */ + //d6ae06a0ee134e9ea7c485c449e8d157 +exports.processInstagramAuthCode = function(serviceAccount, instagramAuthCode, redirectUri, callback){ + + const oauthParams = { + code: instagramAuthCode, + redirect_uri: redirectUri + }; + + oauth2.authorizationCode.getToken(oauthParams) + .then(function (results) { + console.log('Auth code exchange result received:', results); + // We have an Instagram access token and the user identity now. + const instagramUserID = results.user.id; + const profilePic = results.user.profile_picture; + const userName = results.user.full_name; + + // Create a Firebase account and get the Custom Auth Token. + insta.init(serviceAccount); + insta.logInstagramUserIntoFirebase(instagramUserID, userName, profilePic, callback); + }); +}; + +/** + * Passes the auth code to your Mobile application by redirecting to a custom scheme URL. This serves as a fallback in + * case App Link/Universal Links are not supported on the device. + * Native Mobile apps should use this callback. + */ +// exports.handleMobileRedirect = function(req, res){ +// res.redirect(APP_CUSTOM_SCHEME + ':/' + OAUTH_CALLBACK_PATH + '?' + req.originalUrl.split + '?' + [1]); +// }; + +/** + * Exchanges a given Instagram auth code passed in the 'code' URL query parameter for a Firebase auth token and returns + * a Firebase Custom Auth token, Instagram access token and user identity as a JSON object. + * This endpoint is meant to be used by native mobile clients only since no Session Fixation attacks checks are done. + */ +// exports.handleTokenRedirect = function (req, res){ +// console.log('Received auth code:', req.query.code); +// oauth2.authCode.getToken({ +// code: req.query.code, +// redirect_uri: req.protocol + '://' + req.get('host') + OAUTH_MOBILE_CALLBACK_PATH +// }).then(function (results){ +// console.log('Auth code exchange result received:', results); + +// // Create a Firebase Account and get the custom Auth Token. +// insta.createFirebaseAccount(results.user.id, results.user.full_name, results.user.profile_picture, firebaseToken) +// .then(function (firebaseToken){ +// // Send the custom token, access token and profile data as a JSON object. +// res.send(firebaseToken); +// }); +// }); +// }; \ No newline at end of file From 604fa4bd5a29bd19150eee04b500623e4cd5d140 Mon Sep 17 00:00:00 2001 From: edono morrison Date: Sun, 8 Oct 2017 18:09:11 +0100 Subject: [PATCH 3/4] made update to th e instagram functions --- .gitignore | 1 + config.js | 12 ++++++---- core/instagram.js | 33 +++++++++++++++++++------ index.js | 4 ++-- package.json | 2 +- providers/insta_redirect.js | 45 +++++++++++++++++++---------------- providers/social-providers.js | 14 +++++------ 7 files changed, 70 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index dedbee2..a286a33 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.ppk *.glue firebase.json +config.js .DS_Store diff --git a/config.js b/config.js index acdeb28..563248a 100644 --- a/config.js +++ b/config.js @@ -1,7 +1,11 @@ //configuration for token authentication module.exports = { - instagram: { - 'clientId': 'a06298f6337e4dfb9728df87cc6ffeb9', - 'clientSecret': ' ' - } + client: { + 'id': 'a06298f6337e4dfb9728df87cc6ffeb9', + 'secret': 'ad1c1cb68fb84f9b99ed9f9753d53f10' + }, + auth: { + tokenHost: 'https://api.instagram.com', + tokenPath: '/oauth/access_token' + } }; \ No newline at end of file diff --git a/core/instagram.js b/core/instagram.js index 3482c2e..938a2c3 100644 --- a/core/instagram.js +++ b/core/instagram.js @@ -5,15 +5,13 @@ * @returns {Promise} The Firebase custom auth token in a promise. */ -var admin; -exports.init = function (serviceAccount) { var admin = require("firebase-admin"); - admin.initializeApp({ + exports.init = function (serviceAccount) { + admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: 'https://' + serviceAccount.project_id + '.firebaseio.com' }); }; -// Firebase Setup exports.logInstagramUserIntoFirebase = function(instagramID, displayName, photoURL, callback) { if (!admin){ @@ -23,18 +21,24 @@ exports.logInstagramUserIntoFirebase = function(instagramID, displayName, photoU // The UID we'll assign to the user. const uid = 'instagram:' + instagramID; + console.log('this is the user uid: ', uid) // Create or update the user account. var userInfo = { displayName: displayName, photoURL: photoURL }; + console.log('this is the user info: ', userInfo) updateFirebaseUserOrCreateNewUser(uid, userInfo, function(err){ - if (err) - callback(err); + if (err){ + console.log('this is the UPDATE ERROR: ', err) + callback(err); + return; + } else{ const token = admin.auth().createCustomToken(uid); + console.log('this is the your TOKEN: ', token) callback(token); } }); @@ -64,4 +68,19 @@ function createFirebaseUser(uid, userInfo, callback){ .catch(function(error){ callback(error); }) -} \ No newline at end of file +} + +// function createCustomToken(uid, callback){ +// uid = uid; +// admin.auth().createCustomToken(uid) +// .then(function(token){ +// console.log('this is the your TOKEN: ', token) +// callback(token); +// }) +// .catch(function(error){ +// console.log('this is the user error: ', error) + +// callback(error); +// }) +// } +// } \ No newline at end of file diff --git a/index.js b/index.js index ffe97df..5fd2f52 100644 --- a/index.js +++ b/index.js @@ -86,8 +86,8 @@ firebaseAuth.prototype.loginWithTwitter = function(providerToken, callback) { socialProviders.loginWithTwitter(this.apiKey, providerToken, callback); }; -firebaseAuth.prototype.handleRedirect = function(req, res){ - instagram.handleRedirect(req, res); +firebaseAuth.prototype.processInstagramAuthCode = function(serviceAccount, instagramAuthCode, redirectUri, callback){ + instagram.processInstagramAuthCode(serviceAccount, instagramAuthCode, redirectUri, callback); }; module.exports = firebaseAuth; \ No newline at end of file diff --git a/package.json b/package.json index 228802e..7e7a981 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ }, "license": "ISC", "dependencies": { - "firebase-admin": "^5.2.1", + "firebase-admin": "^5.4.1", "node-rest-client": "^3.1.0", "request": "^2.81.0", "request-promise": "^4.2.1", diff --git a/providers/insta_redirect.js b/providers/insta_redirect.js index 6bf6bba..c9c70a9 100644 --- a/providers/insta_redirect.js +++ b/providers/insta_redirect.js @@ -14,10 +14,10 @@ const insta = require('../core/instagram'); // } // }; -var oauth2; -exports.init = function (credentials) { - oauth2 = require('simple-oauth2').create(credentials); -}; +// var oauth2; +// exports.init = function (credentials) { +// oauth2 = require('simple-oauth2').create(credentials); +// }; // const OAUTH_REDIRECT_PATH = '/redirect'; // const OAUTH_CALLBACK_PATH = '/instagram-callback'; @@ -34,25 +34,30 @@ exports.init = function (credentials) { * Exchanges a given Instagram auth code passed in the 'code' URL query parameter for a Firebase auth token. */ //d6ae06a0ee134e9ea7c485c449e8d157 -exports.processInstagramAuthCode = function(serviceAccount, instagramAuthCode, redirectUri, callback){ +exports.processInstagramAuthCode = function(credentials, serviceAccount, instagramAuthCode, redirectUri, callback) { + const oauth2 = require('simple-oauth2').create(credentials); + + const oauthParams = { + code: instagramAuthCode, + redirect_uri: redirectUri + }; - const oauthParams = { - code: instagramAuthCode, - redirect_uri: redirectUri - }; - oauth2.authorizationCode.getToken(oauthParams) - .then(function (results) { - console.log('Auth code exchange result received:', results); - // We have an Instagram access token and the user identity now. - const instagramUserID = results.user.id; - const profilePic = results.user.profile_picture; - const userName = results.user.full_name; + oauth2.authorizationCode.getToken(oauthParams) + .then(function (results) { + console.log('Auth code exchange result received:', results); + // We have an Instagram access token and the user identity now. + const instagramUserID = results.user.id; + const profilePic = results.user.profile_picture; + const userName = results.user.full_name; - // Create a Firebase account and get the Custom Auth Token. - insta.init(serviceAccount); - insta.logInstagramUserIntoFirebase(instagramUserID, userName, profilePic, callback); - }); + // Create a Firebase account and get the Custom Auth Token. + insta.init(serviceAccount); + insta.logInstagramUserIntoFirebase(instagramUserID, userName, profilePic, callback); + }) + .catch(function (error) { + console.log('Auth code exchange error received:', error); + }); }; /** diff --git a/providers/social-providers.js b/providers/social-providers.js index a109191..5107cb6 100644 --- a/providers/social-providers.js +++ b/providers/social-providers.js @@ -1,4 +1,4 @@ -'use strict' +'use strict'; const utils = require('../core/utils'); const endpoints = require('../core/endpoints'); @@ -8,7 +8,7 @@ const ids = { Google: "google.com", Github: "github.com", Twitter: "twitter.com" -} +}; function loginWithProviderID(apiKey, providerToken, providerId, callback){ if (typeof(callback) !== 'function'){ @@ -38,7 +38,7 @@ function loginWithProviderID(apiKey, providerToken, providerId, callback){ requestUri: "http://localhost", returnSecureToken: true, returnIdpCredential: true - } + }; var signInEndpoint = endpoints.getSocialIdentityUrl(apiKey); endpoints.post(signInEndpoint, payload) @@ -59,16 +59,16 @@ exports.loginWithProviderID = loginWithProviderID; exports.loginWithFacebook = function (apiKey, providerToken, callback){ loginWithProviderID(apiKey, providerToken, ids.Facebook, callback) -} +}; exports.loginWithGoogle = function (apiKey, providerToken, callback){ loginWithProviderID(apiKey, providerToken, ids.Google, callback) -} +}; exports.loginWithGithub = function (apiKey, providerToken, callback){ loginWithProviderID(apiKey, providerToken, ids.Github, callback) -} +}; exports.loginWithTwitter = function (apiKey, providerToken, callback){ loginWithProviderID(apiKey, providerToken, ids.Twitter, callback) -} \ No newline at end of file +}; \ No newline at end of file From 88263aec8acdb689f264542d822fc4d58b453954 Mon Sep 17 00:00:00 2001 From: Sirmorrison Date: Sun, 8 Oct 2017 18:11:51 +0100 Subject: [PATCH 4/4] removed the config file --- config.js | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 config.js diff --git a/config.js b/config.js deleted file mode 100644 index 563248a..0000000 --- a/config.js +++ /dev/null @@ -1,11 +0,0 @@ -//configuration for token authentication -module.exports = { - client: { - 'id': 'a06298f6337e4dfb9728df87cc6ffeb9', - 'secret': 'ad1c1cb68fb84f9b99ed9f9753d53f10' - }, - auth: { - tokenHost: 'https://api.instagram.com', - tokenPath: '/oauth/access_token' - } -}; \ No newline at end of file