@@ -38,7 +38,7 @@ const OSM_API_URL = functions.config().osm?.api_url;
3838 * Configure the `osm.client_id` and `osm.client_secret`
3939 * Google Cloud environment variables for the values below to exist
4040 */
41- function osmOAuth2Client ( ) {
41+ function osmOAuth2Client ( client_id , client_secret ) {
4242 const credentials = {
4343 client : {
4444 id : functions . config ( ) . osm ?. client_id ,
@@ -53,35 +53,15 @@ function osmOAuth2Client() {
5353 return simpleOAuth2 . create ( credentials ) ;
5454}
5555
56- /**
57- * Creates a configured simple-oauth2 client for OSM for the web app.
58- * Configure the `osm.client_id_web` and `osm.client_secret_web`
59- * Google Cloud environment variables for the values below to exist
60- */
61- function osmOAuth2ClientWeb ( ) {
62- const credentials = {
63- client : {
64- id : functions . config ( ) . osm ?. client_id_web ,
65- secret : functions . config ( ) . osm ?. client_secret_web ,
66- } ,
67- auth : {
68- tokenHost : OSM_API_URL ,
69- tokenPath : '/oauth2/token' ,
70- authorizePath : '/oauth2/authorize' ,
71- } ,
72- } ;
73- return simpleOAuth2 . create ( credentials ) ;
74- }
75-
7656/**
7757 * Redirects the User to the OSM authentication consent screen.
7858 * Also the '__session' cookie is set for later state verification.
7959 * This function MUST be executed from the user's phone web browser,
8060 * NOT a webview inside MapSwipe, as this would break the promise of
8161 * OAuth that we do not touch their OSM credentials
8262 */
83- export const redirect = ( req : any , res : any ) => {
84- const oauth2 = osmOAuth2Client ( ) ;
63+ function redirect2OsmOauth ( redirect_uri , client_id , client_secret ) {
64+ const oauth2 = osmOAuth2Client ( client_id , client_secret ) ;
8565
8666 cookieParser ( ) ( req , res , ( ) => {
8767 const state =
@@ -97,43 +77,31 @@ export const redirect = (req: any, res: any) => {
9777 httpOnly : true ,
9878 } ) ;
9979 const redirectUri = oauth2 . authorizationCode . authorizeURL ( {
100- redirect_uri : OAUTH_REDIRECT_URI ,
80+ redirect_uri : redirect_uri ,
10181 scope : OAUTH_SCOPES ,
10282 state : state ,
10383 } ) ;
10484 functions . logger . log ( 'Redirecting to:' , redirectUri ) ;
10585 res . redirect ( redirectUri ) ;
10686 } ) ;
87+ }
88+
89+ export const redirect = ( req : any , res : any ) => {
90+ const redirect_uri = OAUTH_REDIRECT_URI ;
91+ const client_id = functions . config ( ) . osm ?. client_id ;
92+ const client_secret = functions . config ( ) . osm ?. client_secret ;
93+ redirect2OsmOauth ( redirect_uri , client_id , client_secret ) ;
10794} ;
10895
10996export const redirectweb = ( req : any , res : any ) => {
110- const oauth2 = osmOAuth2ClientWeb ( ) ;
111-
112- cookieParser ( ) ( req , res , ( ) => {
113- const state =
114- req . cookies . state || crypto . randomBytes ( 20 ) . toString ( 'hex' ) ;
115- functions . logger . log ( 'Setting verification state:' , state ) ;
116- // the cookie MUST be called __session for hosted functions not to
117- // strip it from incoming requests
118- // (https://firebase.google.com/docs/hosting/manage-cache#using_cookies)
119- res . cookie ( '__session' , state . toString ( ) , {
120- // cookie is valid for 1 hour
121- maxAge : 3600000 ,
122- secure : true ,
123- httpOnly : true ,
124- } ) ;
125- const redirectUri = oauth2 . authorizationCode . authorizeURL ( {
126- redirect_uri : OAUTH_REDIRECT_URI_WEB ,
127- scope : OAUTH_SCOPES ,
128- state : state ,
129- } ) ;
130- functions . logger . log ( 'Redirecting to:' , redirectUri ) ;
131- res . redirect ( redirectUri ) ;
132- } ) ;
97+ const redirect_uri = OAUTH_REDIRECT_URI_WEB ;
98+ const client_id = functions . config ( ) . osm ?. client_id_web ;
99+ const client_secret = functions . config ( ) . osm ?. client_secret_web ;
100+ redirect2OsmOauth ( redirect_uri , client_id , client_secret ) ;
133101} ;
134102
135103/**
136- * The OSM OAuth endpoing does not give us any info about the user,
104+ * The OSM OAuth endpoint does not give us any info about the user,
137105 * so we need to get the user profile from this endpoint
138106 */
139107async function getOSMProfile ( accessToken : string ) {
@@ -155,8 +123,8 @@ async function getOSMProfile(accessToken: string) {
155123 * The Firebase custom auth token, display name, photo URL and OSM access
156124 * token are sent back to the app via a deeplink redirect.
157125 */
158- export const token = async ( req : any , res : any , admin : any ) => {
159- const oauth2 = osmOAuth2Client ( ) ;
126+ function fbToken ( redirect_uri , osm_login_link , client_id , client_web ) {
127+ const oauth2 = osmOAuth2Client ( client_id , client_web ) ;
160128
161129 try {
162130 return cookieParser ( ) ( req , res , async ( ) => {
@@ -187,7 +155,7 @@ export const token = async (req: any, res: any, admin: any) => {
187155 // this doesn't work
188156 results = await oauth2 . authorizationCode . getToken ( {
189157 code : req . query . code ,
190- redirect_uri : OAUTH_REDIRECT_URI ,
158+ redirect_uri : redirect_uri ,
191159 scope : OAUTH_SCOPES ,
192160 state : req . query . state ,
193161 } ) ;
@@ -225,7 +193,7 @@ export const token = async (req: any, res: any, admin: any) => {
225193 ) ;
226194 // build a deep link so we can send the token back to the app
227195 // from the browser
228- const signinUrl = `${ APP_OSM_LOGIN_DEEPLINK } ?token=${ firebaseToken } ` ;
196+ const signinUrl = `${ osm_login_link } ?token=${ firebaseToken } ` ;
229197 functions . logger . log ( 'redirecting user to' , signinUrl ) ;
230198 res . redirect ( signinUrl ) ;
231199 } ) ;
@@ -235,89 +203,23 @@ export const token = async (req: any, res: any, admin: any) => {
235203 // back into the app to allow the user to take action
236204 return res . json ( { error : error . toString ( ) } ) ;
237205 }
238- } ;
239-
240206
241- export const tokenweb = async ( req : any , res : any , admin : any ) => {
242- const oauth2 = osmOAuth2ClientWeb ( ) ;
243-
244- try {
245- return cookieParser ( ) ( req , res , async ( ) => {
246- functions . logger . log (
247- 'Received verification state:' ,
248- req . cookies . __session ,
249- ) ;
250- functions . logger . log ( 'Received state:' , req . query . state ) ;
251- // FIXME: For security, we need to check the cookie that was set
252- // in the /redirectweb function on the user's browser.
253- // However, there seems to be a bug in firebase around this.
254- // https://github.com/firebase/firebase-functions/issues/544
255- // and linked SO question
256- // firebase docs mention the need for a cookie middleware, but there
257- // is no info about it :(
258- // cross site cookies don't seem to be the issue
259- // WE just need to make sure the domain set on the cookies is right
260- if ( ! req . cookies . __session ) {
261- throw new Error ( 'State cookie not set or expired. Maybe you took too long to authorize. Please try again.' ) ;
262- } else if ( req . cookies . __session !== req . query . state ) {
263- throw new Error ( 'State validation failed' ) ;
264- }
265- functions . logger . log ( 'Received auth code:' , req . query . code ) ;
266- let results ;
267-
268- try {
269- // TODO: try adding auth data to request headers if
270- // this doesn't work
271- results = await oauth2 . authorizationCode . getToken ( {
272- code : req . query . code ,
273- redirect_uri : OAUTH_REDIRECT_URI_WEB ,
274- scope : OAUTH_SCOPES ,
275- state : req . query . state ,
276- } ) ;
277- } catch ( error : any ) {
278- functions . logger . log ( 'Auth token error' , error , error . data . res . req ) ;
279- }
280- // why is token called twice?
281- functions . logger . log (
282- 'Auth code exchange result received:' ,
283- results ,
284- ) ;
207+ }
285208
286- // We have an OSM access token and the user identity now.
287- const accessToken = results && results . access_token ;
288- if ( accessToken === undefined ) {
289- throw new Error (
290- 'Could not get an access token from OpenStreetMap' ,
291- ) ;
292- }
293- // get the OSM user id and display_name
294- const { id, display_name } = await getOSMProfile ( accessToken ) ;
295- functions . logger . log ( 'osmuser:' , id , display_name ) ;
296- if ( id === undefined ) {
297- // this should not happen, but help guard against creating
298- // invalid accounts
299- throw new Error ( 'Could not obtain an account id from OSM' ) ;
300- }
209+ export const token = async ( req : any , res : any , admin : any ) => {
210+ const redirect_uri = OAUTH_REDIRECT_URI ;
211+ const osm_login_link = APP_OSM_LOGIN_DEEPLINK ;
212+ const client_id = functions . config ( ) . osm ?. client_id ;
213+ const client_secret = functions . config ( ) . osm ?. client_secret ;
214+ fbToken ( redirect_uri , osm_login_link , client_id , client_secret ) ;
215+ } ;
301216
302- // Create a Firebase account and get the Custom Auth Token.
303- const firebaseToken = await createFirebaseAccount (
304- admin ,
305- id ,
306- display_name ,
307- accessToken ,
308- ) ;
309- // build a deep link so we can send the token back to the app
310- // from the browser
311- const signinUrl = `${ APP_OSM_LOGIN_DEEPLINK_WEB } ?token=${ firebaseToken } ` ;
312- functions . logger . log ( 'redirecting user to' , signinUrl ) ;
313- res . redirect ( signinUrl ) ;
314- } ) ;
315- } catch ( error : any ) {
316- // FIXME: this should show up in the user's browser as a bit of text
317- // We should figure out the various error codes available and feed them
318- // back into the app to allow the user to take action
319- return res . json ( { error : error . toString ( ) } ) ;
320- }
217+ export const tokenweb = async ( req : any , res : any , admin : any ) => {
218+ const redirect_uri = OAUTH_REDIRECT_URI_WEB ;
219+ const osm_login_link = APP_OSM_LOGIN_DEEPLINK_WEB ;
220+ const client_id = functions . config ( ) . osm ?. client_id_web ;
221+ const client_secret = functions . config ( ) . osm ?. client_secret_web ;
222+ fbToken ( redirect_uri , osm_login_link , client_id , client_secret ) ;
321223} ;
322224
323225/**
0 commit comments