Automatically sanitize #Args in type-graphql - typegraphql

Is it possible to automatically sanitize the args?
...
#Mutation(returns => Ok)
async signup(#Args() args: args.GetSignupArgs ) {
sanitize(args);
const { name, email, password } = args;
const checkUser = await this.userRepository.findOne({ email })
...

You should be able to do this by injecting a global middleware. See: https://github.com/19majkel94/type-graphql/blob/master/docs/middlewares.md

Related

How do i get data ouside of "post" function?

so i an have express server, and i want to use data that I get outside of post function or in other post functions here is the code
app.post('/bg-login', (req, res) => {
var user;
req.body.email;
req.body.password;
var email1 = req.body.email;
const path = './Databases/User/' + email1 + '.json';
if (fs.existsSync(path)) {
try {
// Note that jsonString will be a <Buffer> since we did not specify an
// encoding type for the file. But it'll still work because JSON.parse() will
// use <Buffer>.toString().
} catch (err) {
return;
}
var user1 = fs.readFileSync('./Databases/User/1.json');
var user = JSON.parse(user1)
} else {
res.redirect("/login-e1");
}
console.log(user);
Error: user is not defined, so how could I get this variable ( user) to work outside POST function
You can just define the variable "user" in the global scope instead of the function scope.

Nuxt - is it possible to check if a user is logged in from SSR?

I created a Nuxt app that uses Django on the backend, i'm using the standard Django Session Authentication, so when i log in from Nuxt, a session cookie is set in my browser.
I've been trying for days to find a way to restrict some pages to authenticated users only, but i don't seem to find any working approach to do that. I need to check if the user is logged in before the page is loaded, so i tried to use a middleware but middleware won't work at all because the middleware is executed from server side (not client side) so there won't be any cookie in the request.
At this point, is there any other way to do this from SSR? Here is my request:
export default async function (context) {
axios.defaults.withCredentials = true;
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//Check if user is authenticated - response is always False
}).catch(function (error) {
//Handle error
});
}
If you are running Nuxt in SSR mode as server, you can access the cookie headers to find out if the user has a certain cookie. Packages like cookieparser (NPM) can easily do that for you.
But as you already found out, you can't do that in a middleware. What you could use instead is the nuxtServerInit action in your store (Docs). This action is run on the server and before any middleware gets executed. In there you can use cookieparser to get the user's cookies, authenticate them and save the any information you need in the store.
Later you can access the store in your middleware and for example redirect the user.
actually you can get cookies in a middleware.... Ill put my example, but the answer above is more correct .
middleware/auth.js
import * as cookiesUtils from '~/utils/cookies'
export default function ({ route, req, redirect }) {
const isClient = process.client
const isServer = process.server
const getItem = (item) => {
// On server
if (isServer) {
const cookies = cookiesUtils.getcookiesInServer(req)
return cookies[item] || false
}
// On client
if (isClient) {
return cookiesUtils.getcookiesInClient(item)
}
}
const token = getItem('token')
const { timeAuthorized } = cookiesUtils.authorizeProps(token)
const setRedirect = (routeName, query) => {
return redirect({
name: routeName,
query: query
? {
redirect: route.fullPath
}
: null
})
}
// strange bug.. nuxt cant redirect '/' to '/login'
if (route.path === '/') {
setRedirect('users')
}
if (!route.path.match(/\/login\/*/g) && !timeAuthorized) {
setRedirect('login', true)
}
}
utils/cookies.js
import Cookie from 'js-cookie'
import jwtDecoded from 'jwt-decode'
/*
TOKEN
*/
// Get server cookie
export const getcookiesInServer = (req) => {
const serviceCookie = {}
if (req && req.headers.cookie) {
req.headers.cookie.split(';').forEach((val) => {
const parts = val.split('=')
serviceCookie[parts[0].trim()] = (parts[1] || '').trim()
})
}
return serviceCookie
}
// Get the client cookie
export const getcookiesInClient = (key) => {
return Cookie.get(key) || false
}
export const setcookiesToken = (token) => {
Cookie.set('token', token)
}
export const removecookiesToken = () => {
Cookie.remove('token')
}
export const authorizeProps = (token) => {
const decodeToken = token && jwtDecoded(token)
const timeAuthorized = (decodeToken.exp > Date.now() / 1000) || false
return {
timeAuthorized
}
}

How to pass next as an argument on Mocha test

I am trying to test a function that checks if the user enter the email and if so it returns true, otherwise it passes an error argument to the next function and then it returns false. The test when the user passes an email it runs succesfully, but the test when the user does not provide an email fails. The error logs is that next is not a function. How is it possible to pass next as argument?
const crypto = require("crypto");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../model/userModel");
const throwsAnError = require("../utils/throwsAnError");
exports.signup = async (req, res, next) => {
const {email, username, password, confirmPassword} = req.body;
if(!checkIfEmailExists(email, next)) {
return;
}
try{
const user = await User.create({
email: email,
userName: username,
password: password,
confirmPassword: confirmPassword
});
res.status(200).json({
message: "success",
data: user
})
}
catch(e){
next(new throwsAnError("Ο χρήστης δεν μπορεί να δημιουργηθεί", 400, e));
console.log("I'm in");
}
};
function checkIfEmailExists(email, next) {
if(!email) {
next(new throwsAnError("Συμπληρώστε το e-mail", 400));
return false;
}
return true;
}
exports.checkIfEmailExists = checkIfEmailExists;
const expect = require("chai").expect;
const authController = require("../controller/authController");
describe("Testing if email exist", function() {
it("should return true if email exists", function() {
expect(authController.checkIfEmailExists("email#email.com")).to.be.true;
})
it("should return false if email does not exist", function() {
expect(authController.checkIfEmailExists(undefined, next)).to.be.false;
})
});
When you call the function you should pass a mock for next, it can be as simple as passing:
() => {} or any other mock (using jest/sinon/etc), depends on the behavior you want.
So change:
expect(authController.checkIfEmailExists("email#email.com")).to.be.true;
to:
expect(authController.checkIfEmailExists("email#email.com", () => {})).to.be.true;
Further, it looks like you're mixing middleware with app-logic: you didn't show us how checkIfEmailExists() looks like and I don't see any good reason to pass in next.
If it's a middleware it should be called as a middleware (from the route) and not explicitly like it's done here.

Mock data initialization being subject to Firestore rules

I'm testing a simple rule:
match /users/{userId} {
allow write, get: if isSignedIn() && userOwner(userId);
}
function isSignedIn(){
return request.auth != null
}
function userOwner(userId){
return userId == request.auth.uid
}
Here is my test:
test("read succeed only if requested user is authenticated user", async () => {
const db = await setup(
{
uid: "testid",
email: "test#test.com"
},
{
"users/testid": {},
"users/anotherid": {}
}
);
const userRef = db.collection("users");
expect(await assertSucceeds(userRef.doc("testid").get()));
expect(await assertFails(userRef.doc("anotherid").get()));
})
And the setup method:
export const setup = async (auth?: any, data?: any) => {
const projectId = `rules-spec-${Date.now()}`;
const app = firebase.initializeTestApp({
projectId,
auth
});
const db = app.firestore();
if (data) {
for (const key in data) {
const ref = db.doc(key);
await ref.set(data[key]);
}
}
await firebase.loadFirestoreRules({
projectId,
rules: fs.readFileSync("firestore.rules").toString()
});
return db;
};
It throws the following error :
FirebaseError: 7 PERMISSION_DENIED:
false for 'create' # L5, Null value error. for 'create' # L9
It seems that when it tries to set the mock data given in setup, it can't because of the write rule. but I don't understand, I load the rules after the database being set.
Any idea what's going on here?
You can try setting the rules to be open before you populate the database.
After the data is set you load the rules you are trying to test.
export const setup = async(auth ? : any, data ? : any) => {
const projectId = `rules-spec-${Date.now()}`;
const app = firebase.initializeTestApp({
projectId,
auth
});
const db = app.firestore();
await firebase.loadFirestoreRules({
projectId,
rules:
"service cloud.firestore {match/databases/{database}/documents" +
"{match /{document=**} {" +
"allow read, write: if true;" +
"}}}",
});
if (data) {
for (const key in data) {
const ref = db.doc(key);
await ref.set(data[key]);
}
}
await firebase.loadFirestoreRules({
projectId,
rules: fs.readFileSync("firestore.rules").toString()
});
return db;
};

next js redux-observable persistent auth token using cookie

I have been trying to implement react server-side-rendering using next, and redux-observable, now i want to implement auth
On signin
click signin
dispatch signin
set signin type
set signin data
call backend api auth/signin
if the response says that token is expired
call backed api auth/refresh using refreshToken
set cookie based on auth/refresh response token
set auth data based on auth/refresh response
else
set cookie based on auth/signin response token
set auth data based on auth/signin response
On accessing pages that needs auth
check for cookies called token
if exists
call backed api auth/me to authorize
if the response says that token is expired
call backed api auth/refresh using refreshToken
set cookie based on auth/refresh response token
set auth data based on auth/refresh
else
set auth data based on auth/me response
else
redirect to signin
Steps above happens inside the epics, as follows
/epics/signin.js
export const signinEpic = (action$, store) => action$
.ofType(SIGNIN)
.mergeMap(() => {
const params = { ... }
return ajax(params)
.concatMap((response) => {
const { name, refreshToken } = response.body
if (refreshToken && name === 'TokenExpiredError') {
const refreshParams = { ... }
return ajax(refreshParams)
.concatMap((refreshResponse) => {
setToken(refreshResponse.body.auth.token)
const me = { ... }
return [
authSetMe(me),
signinSuccess(),
]
})
.catch(error => of(signinFailure(error)))
}
const me = { ... }
setToken(response.body.auth.token)
return [
authSetMe(me),
signinSuccess(),
]
})
.catch(error => of(signinFailure(error)))
})
I did some console.log(Cookies.get('token')) to ensure that the cookie gets saved, and it prints the token just fine, saying that its there, but when i checked under browser console > Application > Cookies, nothing is there
So in auth epic below, the getToken() will always return '' which will always dispatch authMeFailure(error)
/epics/auth.js
// this epic will run on pages that requires auth by dispatching `authMe()`
export const authMeEpic = action$ => action$
.ofType(AUTH_ME)
.mergeMap(() => {
const params = {
...,
data: {
...
Authorization: getToken() ? getToken() : '', // this will always return ''
},
}
return ajax(params)
.mergeMap((response) => {
const { name, refreshToken } = response.body
if (refreshToken && name === 'TokenExpiredError') {
const refreshParams = { ... }
return ajax(refreshParams)
.mergeMap((refreshResponse) => {
setToken(refreshResponse.body.auth.token)
const me = { ... }
return authMeSuccess(me)
})
.catch(error => of(authMeFailure(error)))
}
const me = { ... }
setToken(response.body.auth.token)
return authMeSuccess(me)
})
.catch(error => of(authMeFailure(error)))
})
I use js-cookie for getting and setting cookies
EDIT: i actually prepared an auth lib containing getToken, setToken and removeToken, as follows
import Cookies from 'js-cookie'
export const isAuthenticated = () => {
const token = Cookies.get('token')
return !!token
}
export const getToken = () => Cookies.get('token')
export const setToken = token => Cookies.set('token', token)
export const removeToken = () => Cookies.remove('token')
and yes, i could have just used the setToken() on the epics, was just trying to directly test the cookie set method
UPDATE:
it seems that despite its not being in Console > Application > Cookies, its exists on every pages as it's printing the correct token if i do console.log(getToken()) inside the component render method
But every time i refresh the page, its gone. Kind of like it is being stored in a redux state, which is weird
UPDATE #2:
ok i think i manage to make it work, it turns out that we need 2 types of cookie, server side (the one's generated on refresh) and a client side (persist on navigating), so the reason that i wasn't able to get the token on epics its because it was not passed from the server side (at least this is my understanding)
Inspired by this issue comment on github
yarn add cookie-parser
on ./server.js (you need to have a custom server to be able to do this)
const cookieParser = require('cookie-parser')
...
server.use(cookieParser())
on ./pages/_document.js
export default class extends Document {
static async getInitialProps(...args) {
// ...args in your case would probably be req
const token = args[0].req ? getServerToken(args[0].req) : getToken()
return {
...
token,
}
}
render() {
...
}
}
on ./lib/auth.js or on any place you put your token methods
export const getServerToken = (req) => {
const { token = '' } = req.cookies
return token
}
export const getToken = () => {
return Cookies.get('token') ? Cookies.get('token') : ''
}
I am not 100% understand how this is solving my problem, but i am gonna leave it like this for now