diff --git a/src/controllers/authenticate.js b/src/controllers/authenticate.js
index bcb9d46f..c6b86746 100644
--- a/src/controllers/authenticate.js
+++ b/src/controllers/authenticate.js
@@ -88,13 +88,36 @@ export async function login(options, req, res) {
});
}
-export async function socialLoginCallback(options, req, res) {
+export async function socialLoginCallback(options, service, req, res) {
const { user } = req;
if (await user.isBanned()) {
throw new PermissionError('You have been banned.');
}
+ let script = '';
+ if (user.pendingActivation) {
+ script = `
+ var opener = window.opener;
+ if (opener) {
+ opener.postMessage({
+ pending: true,
+ socialAvatar: ${JSON.stringify(user.avatar)},
+ type: ${JSON.stringify(service)}
+ }, '*');
+ }
+ window.close();
+ `;
+ } else {
+ script = `
+ var opener = window.opener;
+ if (opener) {
+ opener.postMessage({ pending: false }, '*');
+ }
+ window.close();
+ `;
+ }
+
await refreshSession(res, req.uwaveHttp, user, {
...options,
session: 'cookie',
@@ -107,14 +130,41 @@ export async function socialLoginCallback(options, req, res) {
Success
-
+
You can now close this window.
-
+
`);
}
+export async function socialLoginFinish(options, service, req, res) {
+ const { user } = req;
+ const sessionType = req.query.session === 'cookie' ? 'cookie' : 'token';
+
+ if (await user.isBanned()) {
+ throw new PermissionError('You have been banned.');
+ }
+
+ const { username } = req.body;
+
+ user.username = username;
+ user.pendingActivation = undefined;
+ await user.save();
+
+ const { token, socketToken } = await refreshSession(res, req.uwaveHttp, user, {
+ ...options,
+ session: sessionType,
+ });
+
+ return toItemResponse(user, {
+ meta: {
+ jwt: sessionType === 'token' ? token : 'cookie',
+ socketToken,
+ },
+ });
+}
+
export async function getSocketToken(req) {
const { user } = req;
const { authRegistry } = req.uwaveHttp;
diff --git a/src/passport.js b/src/passport.js
index 9c323c47..718b4a01 100644
--- a/src/passport.js
+++ b/src/passport.js
@@ -18,6 +18,13 @@ export default function configurePassport(uw, options) {
});
}
+ async function googleLogin(accessToken, refreshToken, profile) {
+ return socialLogin(accessToken, refreshToken, {
+ id: profile.id,
+ photos: profile.photos,
+ });
+ }
+
async function serializeUser(user) {
return user.id;
}
@@ -36,7 +43,7 @@ export default function configurePassport(uw, options) {
callbackURL: '/auth/service/google/callback',
...options.auth.google,
scope: ['profile'],
- }, callbackify(socialLogin)));
+ }, callbackify(googleLogin)));
}
passport.use('jwt', new JWTStrategy(options.secret, user => uw.getUser(user.id)));
diff --git a/src/routes/authenticate.js b/src/routes/authenticate.js
index b745e0d4..22c8511c 100644
--- a/src/routes/authenticate.js
+++ b/src/routes/authenticate.js
@@ -70,11 +70,16 @@ export default function authenticateRoutes(api, options) {
passport.authenticate('google'),
route(controller.login.bind(null, options)),
)
- // GET /auth/service/google/callback - Finish a social login using Google.
+ // GET /auth/service/google/callback - Receive social login data from Google.
.get(
'/service/google/callback',
passport.authenticate('google'),
- route(controller.socialLoginCallback.bind(null, options)),
+ route(controller.socialLoginCallback.bind(null, options, 'google')),
+ )
+ // POST /auth/service/google/finish - Finish creating an account with Google.
+ .post(
+ '/service/google/finish',
+ route(controller.socialLoginFinish.bind(null, options, 'google')),
);
}