diff --git a/lib/controllers.js b/lib/controllers.js index a9c81fc..340c610 100644 --- a/lib/controllers.js +++ b/lib/controllers.js @@ -74,7 +74,7 @@ Controllers.editStrategy = async (req, res) => { payload.enabled = !!req.body.enabled; - const checkboxes = ['forceUsernameViaEmail', 'usernameViaEmail', 'trustEmailVerified', 'syncFullname', 'syncPicture']; + const checkboxes = ['forceUsernameViaEmail', 'usernameViaEmail', 'trustEmailVerified', 'syncFullname', 'syncPicture', 'fetchPictureWithToken']; checkboxes.forEach((prop) => { payload[prop] = payload.hasOwnProperty(prop) && payload[prop] === 'on' ? 1 : 0; }); diff --git a/library.js b/library.js index 961bb15..414ef6f 100644 --- a/library.js +++ b/library.js @@ -154,6 +154,7 @@ OAuth.getUserProfile = function (name, userRoute, accessToken, done) { const json = JSON.parse(body); const profile = await OAuth.parseUserReturn(name, json); profile.provider = name; + profile.accessToken = accessToken; done(null, profile); } catch (e) { done(e); @@ -277,11 +278,54 @@ OAuth.assignGroups = async ({ user, profile }) => { winston.verbose(`[plugins/sso-auth0] uid ${uid} now a part of ${toJoin.length} these user groups: ${toJoin.join(', ')}`); }; +OAuth.syncPictureViaToken = async (uid, profile, strategy) => { + const enabled = parseInt(strategy.syncPicture, 10) && parseInt(strategy.fetchPictureWithToken, 10); + if (!enabled || !profile.picture || !profile.accessToken) { + return false; + } + + const { uploadedpicture } = await user.getUserFields(uid, ['uploadedpicture']); + if (uploadedpicture) { + return true; + } + + try { + const res = await fetch(profile.picture, { + headers: { Authorization: `Bearer ${profile.accessToken}` }, + }); + if (!res.ok) { + winston.verbose(`[plugin/sso-oauth2-multiple] Picture for uid ${uid} unavailable (${res.status})`); + return false; + } + + const buffer = Buffer.from(await res.arrayBuffer()); + if (!buffer.length) { + return false; + } + + const type = (res.headers.get('content-type') || 'image/jpeg').split(';')[0]; + await user.uploadCroppedPicture({ + callerUid: uid, + uid, + imageData: `data:${type};base64,${buffer.toString('base64')}`, + }); + + return true; + } catch (err) { + winston.warn(`[plugin/sso-oauth2-multiple] Unable to sync picture for uid ${uid}: ${err.message}`); + return false; + } +}; + OAuth.updateProfile = async (uid, profile) => { const fields = ['fullname', 'picture']; const strategy = await OAuth.getStrategy(profile.provider); const allowList = []; + if (await OAuth.syncPictureViaToken(uid, profile, strategy)) { + fields.splice(fields.indexOf('picture'), 1); + } + const payload = fields.reduce((memo, field) => { const setting = `sync${field[0].toUpperCase()}${field.slice(1)}`; if (strategy[setting] && parseInt(strategy[setting], 10)) { diff --git a/static/templates/partials/edit-oauth2-strategy.tpl b/static/templates/partials/edit-oauth2-strategy.tpl index dcc4f65..210b964 100644 --- a/static/templates/partials/edit-oauth2-strategy.tpl +++ b/static/templates/partials/edit-oauth2-strategy.tpl @@ -142,6 +142,18 @@ + +