I am using my express js app as webhook. There is a .get() method only for sending HTML page (Home Page) to browser.
app.get('/', (req, res) => {
//res.send('Hello World!');
res.sendFile(path.join(__dirname, '/views/abc.html'));
});
Now I have another method for handling webhook request as follow.
app.post('/',(req,res)=> {
const text = req.body.text;
const jsonResponse = {
"fulfillmentMessages": [
{
"text": {
"text": [
"Text response from webhook"
]
}
}
]
}
res.status(200).send(jsonResponse);
});
Everything works perfectly, but the above get() method sends response to the webhook which eventually ends up as an error.
I don't want to send this HTML as it is only my website home page.
How do I restrict this method from sending response to webhook.
Related
When I try to make the call from the browser it doesnt work properly
This is the response I get in browser
It is supposed to be like this:
{
"success": true|false,
"challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string, // the hostname of the site where the reCAPTCHA was solved
"error-codes": [...] // optional
}
I'm using vue-recaptcha library on vue3.
<VueRecaptcha
ref="recaptcha"
sitekey="my_key"
#verify="onVerify"
/>
This is the fetch method I use to make the call to google recaptcha api
function onVerify(token) {
fetch(
`https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`,
{
method: 'POST',
}
)
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error('There was an error!', error);
});
}
The thing is when i try the same call in postman it works as it should and responds with the following object:
{
"success": true,
"challenge_ts": "2023-02-07T13:20:44Z",
"hostname": "localhost"
}
I would like to implement Csrf protection with NestJS and Quasar.
But I think I misunderstand something...
btw I'm not doing SSR, so I don't send the form from the back to the view.
Here is the NestJs back-end code:
async function bootstrap() {
const PORT = process.env.PORT;
const app = await NestFactory.create(AppModule, {
cors: true,
bodyParser: false,
});
console.log(`your App is listening on port ${PORT}`);
// Added Cookie-parser to user csurf packages
// Prevent CSRF attack
app.use(cookieParser());
app.use(csurf({ cookie: true }));
await app.listen(PORT);
}
bootstrap();
So I'm just using CookieParser and csurf package.
On my login page I call a "csrf endpoint" just to send a cookie to the view, to send it back with the post call (login).
I still get the "invalid csrf token" AND a CORS error and don't know why....(see screen below), any suggestions to make it works ?
When I try to login, error in the browser:
And error in the back-end:
Same error if I try a request with insomnia.
I thought that the CSRF token is attached to the "web browser" to go back to the back-end with nest request, so why I'm still getting this error ?
Insomnia send the cookie automatically with the right request so the token should go back to the back-end.
Any idea ?
Regards
EDIT:
After many times reading docs, It seems that CSRF protection is for SSR only ? No need to add csrf security with SPA ? Could anyone can confirm ?
EDIT: Here's another work:
The purpose here is to send a request before login to get a csrf token that I can put into a cookie to resend when I login with a POST method.
Here is my endpoint:
import { Controller, Get, Req, Res, HttpCode, Query } from "#nestjs/common";
#Controller("csrf")
export class SecurityController {
#Get("")
#HttpCode(200)
async getNewToken(#Req() req, #Res() res) {
const csrfToken = req.csrfToken();
res.send({ csrfToken });
}
}
Here is what I've done into my main.ts file (I'll explain below):
async function bootstrap() {
const PORT = process.env.PORT;
const app = await NestFactory.create(AppModule, {
cors: {
origin: "*",
methods: ["GET,HEAD,OPTIONS,POST,PUT"],
allowedHeaders: [
"Content-Type",
"X-CSRF-TOKEN",
"access-control-allow-methods",
"Access-Control-Allow-Origin",
"access-control-allow-credentials",
"access-control-allow-headers",
],
credentials: true,
},
bodyParser: false,
});
app.use(cookieParser());
app.use(csurf({ cookie: true }));
console.log(`your App is listening on port ${PORT}`);
await app.listen(PORT);
}
bootstrap();
And here my axiosInstance Interceptors of the request in my VueJS frontend:
axiosInstance.interceptors.request.use(
(req) => {
const token = Cookies.get('my_cookie')
if (token) {
req.headers.common['Authorization'] = 'Bearer ' + token.access_token
}
req.headers['Access-Control-Allow-Origin'] = '*'
req.headers['Access-Control-Allow-Credentials'] = 'true'
req.headers['Access-Control-Allow-Methods'] = 'GET,HEAD,OPTIONS,POST,PUT'
req.headers['Access-Control-Allow-Headers'] =
'access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,content-type,x-csrf-token'
const csrfToken = Cookies.get('X-CSRF-TOKEN')
if (csrfToken) {
req.headers['X-CSRF-TOKEN'] = csrfToken
console.log(req)
}
return req
},
(err) => {
console.log(err)
},
Here the same for repsonse:
axiosInstance.interceptors.response.use(
(response) => {
if (response?.data?.csrfToken) {
const {
data: { csrfToken },
} = response
Cookies.set('X-CSRF-TOKEN', csrfToken)
}
return response
},
And inside my login I make a call on the mounted function of my login component:
async mounted() {
const result = await securityService.getCsrf()
},
So now to explain:
As I said I'm not building a SSR project, that's why I want to send the token into a classic axios reponse and store it in a Cookie (this part is for test I heard that storing a csrf token into a classic cookie is not the right way.)
And for each next request I get the csrf token and "attach" it to the request into the headers, making my headers "custom".
Here is a problem I don't know how to make custom headers works with nestJS and CORS, that's why I try many thing with CORS options in NestJS and writte some custome header before the request go to the back-end but without success, I've got the same error message:
I'm a bit confuse about this problem and CORS/CSRF is a big deal for spa, my questions still the same, with CORS and SameSite cookie attributes, and my api is in a subdomain of my front-end, is it really necessary to make a anti-csrf pattern ?
Btw how can I make my custom headers working and why CORS say to me there is no "Access-Control-Allow-Origin" header but there is:
try to generate csrf token and pass to front on each petition
// main.ts - from NestJs - Backend
// after app.use(csurf({ cookie: true }))
app.use((req: any, res: any, next: any) => {
const token = req.csrfToken()
res.cookie("XSRF-TOKEN", token)
res.locals.csrfToken = token
next()
})
from: https://github.com/nestjs/nest/issues/6552#issuecomment-1175270849
Hi to all i want to change wordpress custom post title via my vue js app on button click but nothing change! The code i use is written bellow
handleController(){
axios.post('https://nice-ardinghelli.185-4-133-211.plesk.page/admin/wp-json/wp/v2/teams/'+this.team.id, {
title: 'changetitle'
})
.then( response => {})
.catch(e => {this.errors.push(e)})
}
},
The message in Postman when call the api url with POST method is written below
{
"code": "rest_cannot_edit",
"message": "Sorry, you are not allowed to edit this post.",
"data": {
"status": 401
}
}
I'm learning Express and I just built a JSON API with CRUD operations to the database
It's working but I'm wondering why my JSON data is formatted like that on the browser
[{"_id":"5f253d105f194d4c8074227d","firstName":"John","lastName":"Doe","age":38,"__v":0},{"_id":"5f253d3a5f194d4c8074227e","firstName":"Jane","lastName":"Doe","age":33,"__v":0}]
I want it to be formatted like
[
{
"_id":"5f253d105f194d4c8074227d",
"firstName":"John",
"lastName":"Doe",
"age":38,
"__v":0},
{
"_id":"5f253d3a5f194d4c8074227e",
"firstName":"Jane",
"lastName":"Doe",
"age":33,
"__v":0}
]
This is the function I use to get the users
router.get("/", async (req, res) => {
try {
const getUsers = await Users.find();
res.json(getUsers);
} catch (err) {
res.json({ message: err.message });
}
});
You only need a JSON formatter for your browser, you can use a formatter like JSON Formatter for Chrome or for JSONView Firefox. Or you can test your API responses with any API client (like Insomnia, Postman, Postwoman...) instead of testing it on your browser
Edit:
If you want (for any reason) to send pre-formatted/human readable JSON responses, you can do so by using JSON.stringify, example:
app.get("/formatted", (req, res) => {
const formattedResponse = JSON.stringify(data, null, 2)
res.type('json').send(formattedResponse)
});
I am building a vue.js client which needs to be authenticated through github oauth using an express server. It's easy to do this using server side rendering but REST API has been troublesome for me.
I have set the homepage url as "http://localhost:3000" where the server runs and I want the authorization callback url to be "http://localhost:8080" (which hosts the client). I am redirecting to "http://localhost:3000/auth/github/redirect" instead, and in its callback redirecting to "http://localhost:8080". The problem I am facing is that I am unable to send user data to the vuejs client through res.redirect. I am not sure if I am doing it the right way.
router.get("/github", passport.authenticate("github"));
router.get(
"/github/redirect",
passport.authenticate("github", { failureRedirect: "/login" }),
(req, res) => {
// res.send(req.user);
res.redirect("http://localhost:8080/"); // req.user should be sent with this
}
);
I have implemented the following approach as a work around :-
A route that returns the user details in a get request :
router.get("/check", (req, res) => {
if (req.user === undefined) {
res.json({});
} else {
res.json({
user: req.user
});
}
});
The client app hits this api right after redirection along with some necessary headers :
checkIfLoggedIn() {
const url = `${API_ROOT}auth/check/`;
return axios(url, {
headers: { "Content-Type": "application/json" },
withCredentials: true
});
}
To enable credentials, we have to pass the following options while configuring cors :
var corsOption = {
origin: true,
credentials: true
};
app.use(cors(corsOption));