How to setup Apple Sign-In using hapi's bell? - authentication

I'm using bell (https://www.npmjs.com/package/bell) for authentication plugin. I used version 10.0.0.
I've setup the configuration in Apple developer site. I got this issue:
ERROR secretOrPrivateKey must be an asymmetric key when using ES256
Here is my apple authentication plugin for hapi
const jwt = require('jsonwebtoken')
const jwksClient = require('jwks-rsa')
const consola = require('consola')
const config = require('../config/server')
const client = jwksClient({
jwksUri: 'https://appleid.apple.com/auth/keys',
timeout: 30000
})
function getSecretKey () {
const claims = {
iss: config.authAppleSecretTeamId,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 86400 * 180,
aud: 'https://appleid.apple.com',
sub: config.authAppleId
}
const token = jwt.sign(claims, config.authAppleSecretPrivateKey, {
algorithm: 'ES256',
keyid: config.authAppleSecretKeyId
})
return token
}
function getApplePublicKey (kid) {
return new Promise((resolve) => {
client.getSigningKey(kid, (_, key) => {
const publicKey = key.getPublicKey()
resolve(publicKey)
})
})
}
const appleProvider = {
auth: 'https://appleid.apple.com/auth/authorize',
token: 'https://appleid.apple.com/auth/token',
name: 'apple',
protocol: 'oauth2',
useParamsAuth: true,
profile: async (credentials, params) => {
const { header } = jwt.decode(params.id_token, { complete: true })
const publicKey = await getApplePublicKey(header.kid)
const resp = jwt.verify(params.id_token, publicKey)
if (config.environment !== 'production') {
console.log('appleProvider -> params, header, resp : ', params, header, resp)
}
const { sub, email, name } = resp
credentials.profile = {
id: sub,
email,
name: {
first: name.firstName || '',
last: name.lastName || ''
}
}
}
}
module.exports.plugin = {
name: 'auth-apple',
register: (server, options) => {
const strategy = {
provider: appleProvider,
providerParams: { response_mode: 'form_post' },
scope: ['name', 'email'],
password: config.authApplePassword,
clientId: config.authAppleId,
clientSecret: getSecretKey(),
location: config.baseUrl,
forceHttps: true,
isSecure: true
}
if (['development', 'localtest'].includes(config.environment)) {
consola.log(`Un-setting https for Apple auth strategy in ${config.environment}`)
delete strategy.location
delete strategy.forceHttps
strategy.isSecure = false
}
server.auth.strategy('apple', 'bell', strategy)
}
}
Also bell doesn't have default provider for Apple sign-in, we have to write it.
Any suggestion or guidance will be appreciated

Related

How can I set Next-Auth callback url? and next-auth session return null

I want to set login, logout callback url.
So, I set the callback url like this.
//signIn
const signInResult = await signIn("credentials", {
message,
signature,
redirect: false,
callbackUrl: `${env.nextauth_url}`,
});
//signOut
signOut({ callbackUrl: `${env.nextauth_url}`, redirect: false });
But, When I log in, I look at the network tab.
api/auth/providers, api/auth/callback/credentials? reply with
callbackUrl(url) localhost:3000
It's api/auth/callback/credentials? reply.
It's api/auth/providers reply
and api/auth/session reply empty object.
When I run on http://localhost:3000, everything was perfect.
But, After deploy, the login is not working properly.
How can I fix the error?
I added [...next-auth] code.
import CredentialsProvider from "next-auth/providers/credentials";
import NextAuth from "next-auth";
import Moralis from "moralis";
import env from "env.json";
export default NextAuth({
providers: [
CredentialsProvider({
name: "MoralisAuth",
credentials: {
message: {
label: "Message",
type: "text",
placeholder: "0x0",
},
signature: {
label: "Signature",
type: "text",
placeholder: "0x0",
},
},
async authorize(credentials: any): Promise<any> {
try {
const { message, signature } = credentials;
await Moralis.start({
apiKey: env.moralis_api_key,
});
const { address, profileId } = (
await Moralis.Auth.verify({ message, signature, network: "evm" })
).raw;
if (address && profileId) {
const user = { address, profileId, signature };
if (user) {
return user;
}
}
} catch (error) {
console.error(error);
return null;
}
},
}),
],
pages: {
signIn: "/",
signOut: "/",
},
session: {
maxAge: 3 * 24 * 60 * 60,
},
callbacks: {
async jwt({ token, user }) {
user && (token.user = user);
return token;
},
async session({ session, token }: any) {
session.user = token.user;
return session;
},
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
if (url.startsWith("/")) return `${baseUrl}${url}`;
// Allows callback URLs on the same origin
else if (new URL(url).origin === baseUrl) return url;
return baseUrl;
},
},
secret: env.nextauth_secret,
});

Testing authentication with Auth0 in a full stack application with Cypress

I’m working on a full-stack NestJS application, integrating with Auth0 using the express-openid-connect library. I’m using Cypress for e2e tests, and I’m trying to find a way of testing my login using Cypress.
I found this article - https://auth0.com/blog/end-to-end-testing-with-cypress-and-auth0/, but it seems to be very much tied to a React application. I’m calling the /oauth/token API endpoint, and I get a response, but I’m unsure how to build out my callback URL to log me in to the application. Here’s what I have so far:
Cypress.Commands.add('login', () => {
cy.session('logged in user', () => {
const options = {
method: 'POST',
url: `${Cypress.env('OAUTH_DOMAIN')}/oauth/token`,
body: {
grant_type: 'password',
username: Cypress.env('AUTH_USERNAME'),
password: Cypress.env('AUTH_PASSWORD'),
scope: 'openid profile email',
audience: `${Cypress.env('OAUTH_DOMAIN')}/api/v2/`,
client_id: Cypress.env('OAUTH_CLIENT_ID'),
client_secret: Cypress.env('OAUTH_CLIENT_SECRET'),
},
};
cy.request(options).then((response) => {
// What do I do here?
});
});
});
Any pointers would be gratefully recieved!
I ended up sorting this out by using Puppeteer to handle my login, stopping at the point of redirection to the callback URL and returning the cookies and callback URL to Cypress, as detailed in this article:
https://sandrino.dev/blog/writing-cypress-e2e-tests-with-auth0
Things have changed a bit since then, and with the introduction of Cypress's experimentalSessionSupport it's a bit simpler. I ended up whittling the solution down to having the following in my Cypress setup:
// cypress/plugins/auth0.js
const puppeteer = require('puppeteer');
const preventApplicationRedirect = function (callbackUrl) {
return (request) => {
const url = request.url();
if (request.isNavigationRequest() && url.indexOf(callbackUrl) === 0)
request.respond({ body: url, status: 200 });
else request.continue();
};
};
const writeUsername = async function writeUsername({ page, options } = {}) {
await page.waitForSelector('#username');
await page.type('#username', options.username);
};
const writePassword = async function writeUsername({ page, options } = {}) {
await page.waitForSelector('#password', { visible: true });
await page.type('#password', options.password);
};
const clickLogin = async function ({ page } = {}) {
await page.waitForSelector('button[type="submit"]', {
visible: true,
timeout: 5000,
});
const [response] = await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle2' }),
page.click('button[type="submit"]'),
]);
return response;
};
exports.Login = async function (options = {}) {
const browser = await puppeteer.launch({
headless: options.headless,
args: options.args || ['--no-sandbox', '--disable-setuid-sandbox'],
});
const page = await browser.newPage();
try {
await page.setViewport({ width: 1280, height: 800 });
await page.setRequestInterception(true);
page.on('request', preventApplicationRedirect(options.callbackUrl));
await page.goto(options.loginUrl);
await writeUsername({ page, options });
await writePassword({ page, options });
const response = await clickLogin({ page, options });
if (response.status() >= 400) {
throw new Error(
`'Login with user ${
options.username
} failed, error ${response.status()}`,
);
}
const url = response.url();
if (url.indexOf(options.callbackUrl) !== 0) {
throw new Error(`User was redirected to unexpected location: ${url}`);
}
const { cookies } = await page._client.send('Network.getAllCookies', {});
return {
callbackUrl: url,
cookies,
};
} finally {
await page.close();
await browser.close();
}
};
// cypress/plugins/index.js
const auth0 = require('./auth0');
module.exports = (on, config) => {
require('dotenv').config({ path: '.env.test' });
config.env.AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
config.env.AUTH_USERNAME = process.env.AUTH_USERNAME;
config.env.AUTH_PASSWORD = process.env.AUTH_PASSWORD;
on('task', {
LoginPuppeteer(options) {
return auth0.Login(options);
},
});
return config;
};
// cypress/support/commands.js
const { getUnixTime } = require('date-fns');
/*
* Create the cookie expiration.
*/
function getFutureTime(minutesInFuture) {
const time = new Date(new Date().getTime() + minutesInFuture * 60000);
return getUnixTime(time);
}
/**
* Create a cookie object.
* #param {*} cookie
*/
function createCookie(cookie) {
return {
name: cookie.name,
value: cookie.value,
options: {
domain: `${cookie.domain.trimLeft('.')}`,
expiry: getFutureTime(15),
httpOnly: cookie.httpOnly,
path: cookie.path,
sameSite: cookie.sameSite,
secure: cookie.secure,
session: cookie.session,
},
};
}
/**
* Login via puppeteer and return the redirect url and cookies.
*/
function login() {
return cy.task('LoginPuppeteer', {
username: Cypress.env('AUTH_USERNAME'),
password: Cypress.env('AUTH_PASSWORD'),
loginUrl: 'http://localhost:3000/login',
callbackUrl: 'http://localhost:3000/callback',
});
}
/**
* Login with Auth0.
*/
Cypress.Commands.add('loginAuth0', () => {
cy.session('logged in user', () => {
login().then(({ cookies, callbackUrl }) => {
console.log(cookies);
cookies
.map(createCookie)
.forEach((c) => cy.setCookie(c.name, c.value, c.options));
cy.visit(callbackUrl);
});
});
});
You can then use cy.loginAuth0() in your app to login with a real Auth0 instance. Make sure you have "experimentalSessionSupport": true in your cypress.json. That way you'll only have to perform this (admittedly long winded) task only once in your test suite!

onRemoteStreamListener doesn't get triggered on the Initiator's Side (Web App)

I am trying to build a video chat application between 2 users using the sdk provided by Connecty Cube everything works fine so far till.
User 1 (caller) : initiates the call
User 2 (opponent) : receives the call and accepts it
User 1 & User 2 : should get a call back function onRemoteStreamListener in order to start the Video Session between them
What actually happens User 2 only gets the Event for OnRemoteStreamListener and could view/hear User 1, while onRemoteStreamListener doesn't get triggered in User 1 side. I am not sure what is the problem as I have been going through the documentation provided by Connecty Cube and having it as my reference for the integration
link: https://developers.connectycube.com/js/videocalling?id=accept-a-call
ConnectyCube SDK Version : 3.9.1
Here are samples for the code:
User 1 (Caller Code)
async startVideoSession() {
try {
const {
dispatch,
getters: {
getConnectyCubeSessionInfo,
getUserData,
getSelectedVideoAppointement
}
} = this.$store;
const patientConnectyCubeUserResponse = await dispatch(
"getUserFromConnectyCube",
{
sessionInfo: getConnectyCubeSessionInfo,
email: getSelectedVideoAppointement.patient.email
}
);
const doctorConnectyCubeUserResponse = await dispatch(
"getUserFromConnectyCube",
{
sessionInfo: getConnectyCubeSessionInfo,
email: getUserData.email
}
);
const {
Credentials: { appId }
} = connectyCubeClient;
const client = new ConnectyCube();
await client.init({ appId, token: getConnectyCubeSessionInfo.token });
await client.createSession({
login: ########,
password: ##########
});
const token = client.service.sdkInstance.session.token;
await client.chat.connect({
userId: doctorConnectyCubeUserResponse.user.id,
password: token
});
const isConnected = await client.chat.isConnected;
if (isConnected) {
const calleesIds = [patientConnectyCubeUserResponse.user.id]; // User's ids
const sessionType = client.videochat.CallType.VIDEO; // AUDIO is also possible
const additionalOptions = { bandwidth: 256 };
const session = await client.videochat.createNewSession(
calleesIds,
sessionType,
additionalOptions
);
const mediaParams = {
audio: true,
video: true,
options: {
muted: true,
mirror: true
}
};
await session
.getUserMedia(mediaParams)
.then(localStream => {
session.attachMediaStream("doctor-video", localStream);
const extension = {};
session.call(extension, error => {
console.log(error);
});
})
.catch(err => {
console.error(err);
});
console.log("last console.log");
client.videochat.onAcceptCallListener = this.onAcceptCallListener;
// client.videochat.onUserNotAnswerListener = function(session, userId) {
// console.log("call refused");
// };
client.videochat.onSessionConnectionStateChangedListener = function(
session,
userID,
connectionState
) {
console.log("Connection state => \n", connectionState);
};
client.videochat.onRemoteStreamListener = this.OnRemoteStreamListener;
}
} catch (err) {
console.log("ERRRRRROR", err);
}
}
OnRemoteStreamListener(session, userId, remoteStream) {
// attach the remote stream to DOM element
console.log("STREAM FROM DOCTOR");
session.attachMediaStream("patient-video", remoteStream);
},
User 2 (opponent code)
async initalizeConnectyCube() {
const {
getters: { getPatientData }
} = this.$store;
const client = new ConnectyCube();
const { Credentials, Config } = connectyCubeClient;
await client.init(Credentials, Config);
const sessionInfo = await client.createSession();
await client.init({ appId: Credentials.appId, token: sessionInfo.token });
const sessionStatus = await client.createSession({
login: ########,
password: ########
});
const token = client.service.sdkInstance.session.token;
await client.chat.connect({
userId: sessionStatus.user.id,
password: token
});
const isUserConnected = await client.chat.isConnected;
if (isUserConnected) {
client.videochat.onCallListener = this.handleOnCallListener;
client.videochat.onRemoteStreamListener = this.handleOnRemoteStreamListener;
}
}
handleOnRemoteStreamListener(session, userID, remoteStream) {
// attach the remote stream to DOM element
console.log("STREAM FROM CALLER");
session.attachMediaStream("patient-video", remoteStream);
}

Apollo subscriptions JWT authentication

I am using Robin Wieruch's fullstack boilerplate but it is missing authentication for subscriptions. It uses JWT token for sessions and it is working fine for http but for ws auth is completely missing.
I need to pass user trough context for subscriptions as well, I need session info in subscriptions resolver to be able to decide weather I should fire subscription or not.
I did search Apollo docs, I saw I should use onConnect: (connectionParams, webSocket, context) function, but there is no fully functional fullstack example, I am not sure how to pass JWT from client to be able to get it in webSocket object.
Here is what I have so far:
Server:
import express from 'express';
import {
ApolloServer,
AuthenticationError,
} from 'apollo-server-express';
const app = express();
app.use(cors());
const getMe = async req => {
const token = req.headers['x-token'];
if (token) {
try {
return await jwt.verify(token, process.env.SECRET);
} catch (e) {
throw new AuthenticationError(
'Your session expired. Sign in again.',
);
}
}
};
const server = new ApolloServer({
introspection: true,
typeDefs: schema,
resolvers,
subscriptions: {
onConnect: (connectionParams, webSocket, context) => {
console.log(webSocket);
},
},
context: async ({ req, connection }) => {
// subscriptions
if (connection) {
return {
// how to pass me here as well?
models,
};
}
// mutations and queries
if (req) {
const me = await getMe(req);
return {
models,
me,
secret: process.env.SECRET,
};
}
},
});
server.applyMiddleware({ app, path: '/graphql' });
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
const isTest = !!process.env.TEST_DATABASE_URL;
const isProduction = process.env.NODE_ENV === 'production';
const port = process.env.PORT || 8000;
httpServer.listen({ port }, () => {
console.log(`Apollo Server on http://localhost:${port}/graphql`);
});
Client:
const httpLink = createUploadLink({
uri: 'http://localhost:8000/graphql',
fetch: customFetch,
});
const wsLink = new WebSocketLink({
uri: `ws://localhost:8000/graphql`,
options: {
reconnect: true,
},
});
const terminatingLink = split(
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return (
kind === 'OperationDefinition' && operation === 'subscription'
);
},
wsLink,
httpLink,
);
const authLink = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => {
const token = localStorage.getItem('token');
if (token) {
headers = { ...headers, 'x-token': token };
}
return { headers };
});
return forward(operation);
});
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) => {
console.log('GraphQL error', message);
if (message === 'UNAUTHENTICATED') {
signOut(client);
}
});
}
if (networkError) {
console.log('Network error', networkError);
if (networkError.statusCode === 401) {
signOut(client);
}
}
});
const link = ApolloLink.from([authLink, errorLink, terminatingLink]);
const cache = new InMemoryCache();
const client = new ApolloClient({
link,
cache,
resolvers,
typeDefs,
});
You need to use connectionParams to set the JWT from the client-side. Below is the code snippet using the angular framework:
const WS_URI = `wss://${environment.HOST}:${environment.PORT}${
environment.WS_PATH
}`;
const wsClient = subscriptionService.getWSClient(WS_URI, {
lazy: true,
// When connectionParams is a function, it gets evaluated before each connection.
connectionParams: () => {
return {
token: `Bearer ${authService.getJwt()}`
};
},
reconnect: true,
reconnectionAttempts: 5,
connectionCallback: (error: Error[]) => {
if (error) {
console.log(error);
}
console.log('connectionCallback');
},
inactivityTimeout: 1000
});
const wsLink = new WebSocketLink(wsClient);
In your server-side, you are correct, using onConnect event handler to handle the JWT. E.g.
const server = new ApolloServer({
typeDefs,
resolvers,
context: contextFunction,
introspection: true,
subscriptions: {
onConnect: (
connectionParams: IWebSocketConnectionParams,
webSocket: WebSocket,
connectionContext: ConnectionContext,
) => {
console.log('websocket connect');
console.log('connectionParams: ', connectionParams);
if (connectionParams.token) {
const token: string = validateToken(connectionParams.token);
const userConnector = new UserConnector<IMemoryDB>(memoryDB);
let user: IUser | undefined;
try {
const userType: UserType = UserType[token];
user = userConnector.findUserByUserType(userType);
} catch (error) {
throw error;
}
const context: ISubscriptionContext = {
// pubsub: postgresPubSub,
pubsub,
subscribeUser: user,
userConnector,
locationConnector: new LocationConnector<IMemoryDB>(memoryDB),
};
return context;
}
throw new Error('Missing auth token!');
},
onDisconnect: (webSocket: WebSocket, connectionContext: ConnectionContext) => {
console.log('websocket disconnect');
},
},
});
server-side: https://github.com/mrdulin/apollo-graphql-tutorial/blob/master/src/subscriptions/server.ts#L72
client-side: https://github.com/mrdulin/angular-apollo-starter/blob/master/src/app/graphql/graphql.module.ts#L38

Hapi Lab The following leaks were detected:lr

Here Hapi Lab why Test failed when all the tests are passed why the test is failed.
In this new question why I get The following leaks were detected:lr even if there is no global var in the code.
Running this simple test
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var server = require('../../');
lab.experiment('Users', function () {
lab.test('create joi required', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
lab.test('create', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload:{
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var token = response.result.token;
var payload = options.payload;
Code.expect(response.statusCode).to.equal(201);
done();
});
});
});
2 tests complete
Test duration: 363 ms
The following leaks were detected:lr
but I don't see any lr var !
and the strange is if I run this
payload.passdword
instead of
payload.password
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var server = require('../../');
lab.experiment('Users', function () {
lab.test('create joi required', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
lab.test('create', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload:{
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
passdword: 'mysecret'
}
};
server.inject(options, function(response) {
var token = response.result.token;
var payload = options.payload;
Code.expect(response.statusCode).to.equal(201);
done();
});
});
});
I've got
1 of 2 tests failed
Test duration: 73 ms
No global variable leaks detected
with no warning about lr var.
So I don't know which way to turn :(
Can help me, please ?
UPDATE
controller
'use strict';
/**
* Module dependencies.
*/
var BcryptUtil = require('../utils/bcrypt');
var JwtUtil = require('../utils/jwt');
var Models = require('../models');
var ReplyUtil = require('../utils/reply');
var User = Models.users;
exports.create = function create(request, reply) {
var params = request.payload;
params.password = BcryptUtil.generateHash(params.password);
params.roles =JSON.stringify(['user']);
User
.create(params)
.then(function(user) {
var token = JwtUtil.getUserToken(user);
var redisClient = request.server.plugins['hapi-redis'].client;
redisClient.set('user_'+user.userId, token);
return reply(ReplyUtil.ok(token)).created('/api/users/' + user.userId);
})
.catch(function(err){
if(err instanceof Models.Sequelize.ValidationError){
return reply(ReplyUtil.badData(err,params));
}
return reply(ReplyUtil.badImplementation(err));
});
};
exports.findAll = function (request, reply) {
User
.findAll({
order: [['createdAt','DESC']],
attributes: ['userId', 'firstname', 'lastname', 'username', 'email']
})
.then(function(users) {
return reply(ReplyUtil.ok(users));
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.findById = function (request, reply) {
var userId = request.params.userId;
User
.findById(
userId,
{
attributes: ['userId', 'firstname', 'lastname', 'username', 'email']
})
.then(function(user) {
if(!user){
return reply(ReplyUtil.notFound({userId:userId}));
}
return reply(ReplyUtil.ok(user));
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.update = function (request, reply) {
var userId = request.params.userId;
var params =request.payload;
User
.update(params,{
where: {
userId: userId
}
})
.then(function(rows) {
var affectedRows = rows.pop();
if(!affectedRows){
return reply(ReplyUtil.notFound({userId:userId}));
}
return reply(ReplyUtil.ok(affectedRows));
})
.catch(function(err){
if(err instanceof Models.Sequelize.ValidationError){
return reply(ReplyUtil.badData(err,params));
}
return reply(ReplyUtil.badImplementation(err));
});
};
exports.destroy = function (request, reply) {
var userId = request.params.userId;
User
.destroy({
where: {
userId: userId
}
})
.then(function(rows) {
if(!rows){
return reply(ReplyUtil.notFound({userId:userId}));
}
return reply(ReplyUtil.ok(rows));
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.signIn = function (request, reply) {
var params = request.payload;
User
.findOne({
where: {
email: params.email
}
})
.then(function(user) {
if(!user){
return reply(ReplyUtil.invalidPassword());
}
if(BcryptUtil.authenticate(params.password, user.password)){
var token = JwtUtil.getUserToken(user);
var redisClient = request.server.plugins['hapi-redis'].client;
redisClient.set('user_'+user.userId, token);
return reply(ReplyUtil.ok(token));
}
return reply(ReplyUtil.invalidPassword());
})
.catch(function(err){
return reply(ReplyUtil.badImplementation(err));
});
};
exports.logOut = function (request, reply) {
var userId = request.auth.credentials.jti;
var redisClient = request.server.plugins['hapi-redis'].client;
redisClient.del('user_'+userId);
return reply();
};
exports.methodNotAllowed = function (request, reply) {
return reply( ReplyUtil.methodNotAllowed() );
};
route
'use strict';
/**
* Module dependencies.
*/
var User = require('../controllers/users');
var Validator = require('../validations/users');
/**
* Resource configuration.
*/
var internals = {};
internals.resourcePath = '/users';
module.exports = function() {
return [
{
method: 'POST',
path: internals.resourcePath,
config : {
handler: User.create,
validate: Validator.create
}
},
{
method: 'GET',
path: internals.resourcePath,
config : {
handler : User.findAll,
auth: {
strategy: 'token',
scope: ['admin']
}
}
},
{
method: 'GET',
path: internals.resourcePath + '/{userId}',
config : {
handler : User.findById,
validate: Validator.findById,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: 'PUT',
path: internals.resourcePath + '/{userId}',
config : {
handler: User.update,
validate: Validator.update,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: 'DELETE',
path: internals.resourcePath + '/{userId}',
config : {
handler: User.destroy,
validate: Validator.destroy,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: 'POST',
path: internals.resourcePath + '/signin',
config : {
handler: User.signIn,
validate: Validator.signIn
}
},
{
method: 'GET',
path: internals.resourcePath + '/logout',
config : {
handler : User.logOut,
auth: {
strategy: 'token',
scope: ['user']
}
}
},
{
method: '*',
path: internals.resourcePath + '/{somethingss*}',
config : {
handler: User.methodNotAllowed
}
}
];
}();
I no I am a little late, but just in case anyone else has this problem. It's a problem with bcrypt. I had a similar problem where whenever I used bcrypt-nodejs it would give me The following leaks were detected:lr, password, but when I changed to reqular bycrypt it worked with no leaks. Try updating your bycrypt version.
Just add all leakimg elements to ignore list
"test": "lab -c -L -I 'Reflect,core,_babelPolyfill,regeneratorRuntime,__core-js_shared__ css'",