Asp.Net Core Web Api project is blocking calls from front end Vue.Js project (Cors Error) [duplicate] - asp.net

I have an app made with React, Node.js and Socket.io
I deployed Node backend to heroku , frontend to Netlify
I know that CORS errors is related to server but no matter what I add, it just cant go through that error in the picture below.
I also added proxy script to React's package.json as "proxy": "https://googledocs-clone-sbayrak.herokuapp.com/"
And here is my server.js file;
const mongoose = require('mongoose');
const Document = require('./Document');
const dotenv = require('dotenv');
const path = require('path');
const express = require('express');
const http = require('http');
const socketio = require('socket.io');
dotenv.config();
const app = express();
app.use(cors());
const server = http.createServer(app);
const io = socketio(server, {
cors: {
origin: 'https://googledocs-clone-sbayrak.netlify.app/',
methods: ['GET', 'POST'],
},
});
app.get('/', (req, res) => {
res.status(200).send('hello!!');
});
const connectDB = async () => {
try {
const connect = await mongoose.connect(process.env.MONGODB_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
console.log('MongoDB Connected...');
} catch (error) {
console.error(`Error : ${error.message}`);
process.exit(1);
}
};
connectDB();
let defaultValue = '';
const findOrCreateDocument = async (id) => {
if (id === null) return;
const document = await Document.findById({ _id: id });
if (document) return document;
const result = await Document.create({ _id: id, data: defaultValue });
return result;
};
io.on('connection', (socket) => {
socket.on('get-document', async (documentId) => {
const document = await findOrCreateDocument(documentId);
socket.join(documentId);
socket.emit('load-document', document.data);
socket.on('send-changes', (delta) => {
socket.broadcast.to(documentId).emit('receive-changes', delta);
});
socket.on('save-document', async (data) => {
await Document.findByIdAndUpdate(documentId, { data });
});
});
console.log('connected');
});
server.listen(process.env.PORT || 5000, () =>
console.log(`Server has started.`)
);
and this is where I make request from frontend;
import Quill from 'quill';
import 'quill/dist/quill.snow.css';
import { useParams } from 'react-router-dom';
import { io } from 'socket.io-client';
const SAVE_INTERVAL_MS = 2000;
const TextEditor = () => {
const [socket, setSocket] = useState();
const [quill, setQuill] = useState();
const { id: documentId } = useParams();
useEffect(() => {
const s = io('https://googledocs-clone-sbayrak.herokuapp.com/');
setSocket(s);
return () => {
s.disconnect();
};
}, []);
/* below other functions */
/* below other functions */
/* below other functions */
}

TL;DR
https://googledocs-clone-sbayrak.netlify.app/ is not an origin. Drop that trailing slash.
More details about the problem
No trailing slash allowed in the value of the Origin header
According to the CORS protocol (specified in the Fetch standard), browsers never set the Origin request header to a value with a trailing slash. Therefore, if a page at https://googledocs-clone-sbayrak.netlify.app/whatever issues a cross-origin request, that request's Origin header will contain
https://googledocs-clone-sbayrak.netlify.app
without any trailing slash.
Byte-by-byte comparison on the server side
You're using Socket.IO, which relies on the Node.js cors package. That package won't set any Access-Control-Allow-Origin in the response if the request's origin doesn't exactly match your CORS configuration's origin value (https://googledocs-clone-sbayrak.netlify.app/).
Putting it all together
Obviously,
'https://googledocs-clone-sbayrak.netlify.app' ===
'https://googledocs-clone-sbayrak.netlify.app/'
evaluates to false, which causes the cors package not to set any Access-Control-Allow-Origin header in the response, which causes the CORS check to fail in your browser, hence the CORS error you observed.
Example from the Fetch Standard
Section 3.2.5 of the Fetch Standard even provides an enlightening example of this mistake,
Access-Control-Allow-Origin: https://rabbit.invalid/
and explains why it causes the CORS check to fail:
A serialized origin has no trailing slash.

Looks like you haven't imported the cors package. Is it imported anywhere else?
var cors = require('cors') // is missing

Related

how to remove # from URL when using ssr with useHash

I try to run my app with ssr universal In Angular, when I try useHash the html page work fine in all pages but with # ex: http://localhost:4200/#/some-url
Also when I remove useHash the ssr work but just In home page
this test in server not in locale (in locale work fine) any soulotion please
This my server.ts
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
const distFolder = join(process.cwd(), 'dist/calculatorFitness/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run(): void {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';

Firebase cloud functions Appcheck for https.onRequest

As per documentation we can add appcheck as below,
exports.yourCallableFunction = functions.https.onCall((data, context) => {
// context.app will be undefined if the request doesn't include a valid
// App Check token.
if (context.app == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called from an App Check verified app.')
}
});
My question right now is how do I need to add app-check for below scenario?
exports.date = functions.https.onRequest((req, res) => {
});
In the client, get an appCheck token from Firebase. Send it in a header to your function. Get the token from the req object's headers. Verify the the token with firebase-admin. I'll include the documentation for the client below, then the gist of how I implemented it client side with Apollo-client graphql. Then I'll include the documentation for the backend, then the gist of how I implemented the backend, again with Apollo.
client (from the documentation):
const { initializeAppCheck, getToken } = require('firebase/app-check');
const appCheck = initializeAppCheck(
app,
{ provider: provider } // ReCaptchaV3Provider or CustomProvider
);
const callApiWithAppCheckExample = async () => {
let appCheckTokenResponse;
try {
appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ false);
} catch (err) {
// Handle any errors if the token was not retrieved.
return;
}
// Include the App Check token with requests to your server.
const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', {
headers: {
'X-Firebase-AppCheck': appCheckTokenResponse.token,
}
});
// Handle response from your backend.
};
client (gist from my implementation)
import { setContext } from "#apollo/client/link/context";
import { app } from '../firebase/setup';
import { initializeAppCheck, ReCaptchaV3Provider, getToken } from "firebase/app-check"
let appCheck
let appCheckTokenResponse
const getAppCheckToken = async () => {
const appCheckTokenResponsePromise = await getToken(appCheck, /* forceRefresh= */ false)
appCheckTokenResponse = appCheckTokenResponsePromise
}
const authLink = setContext(async (_, { headers }) => {
if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_ENV === 'production') {
appCheck = initializeAppCheck(app, {
provider: new ReCaptchaV3Provider('my_public_key_from_recaptcha_V3'),
isTokenAutoRefreshEnabled: true
})
await getAppCheckToken()
}
return {
headers: {
...headers,
'X-Firebase-AppCheck': appCheckTokenResponse?.token,
},
}
})
backend / server (from the documentation)
const express = require('express');
const app = express();
const firebaseAdmin = require('firebase-admin');
const firebaseApp = firebaseAdmin.initializeApp();
const appCheckVerification = async (req, res, next) => {
const appCheckToken = req.header('X-Firebase-AppCheck');
if (!appCheckToken) {
res.status(401);
return next('Unauthorized');
}
try {
const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken);
// If verifyToken() succeeds, continue with the next middleware
// function in the stack.
return next();
} catch (err) {
res.status(401);
return next('Unauthorized');
}
}
app.get('/yourApiEndpoint', [appCheckVerification], (req, res) => {
// Handle request.
});
backend / server (gist from my implementation)
import { https } from 'firebase-functions'
import gqlServer from './graphql/server'
const functions = require('firebase-functions')
const env = process.env.ENV || functions.config().config.env
const server = gqlServer()
const api = https.onRequest((req, res) => {
server(req, res)
})
export { api }
. . .
import * as admin from 'firebase-admin';
const functions = require('firebase-functions');
const env = process.env.ENV || functions.config().config.env
admin.initializeApp()
appCheckVerification = async (req: any, res: any) => {
const appCheckToken = req.header('X-Firebase-AppCheck')
if (!appCheckToken) {
return false
}
try {
const appCheckClaims = await admin.appCheck().verifyToken(appCheckToken);
return true
} catch (error) {
console.error(error)
return false
}
}
. . .
const apolloServer = new ApolloServer({
introspection: isDevelopment,
typeDefs: schema,
resolvers,
context: async ({ req, res }) => {
if (!isDevelopment && !isTest) {
const appCheckVerification = await appCheckVerification(req, res)
if (!appCheckVerification) throw Error('Something went wrong with verification')
}
return { req, res, }
}
If you enforce app check in Cloud Functions it will only allow calls from apps that are registered in your project.
I'm not sure if that is sufficient for your use-case though, as I doubt most apps where you can provide a web hook will have implemented app attestation - which is how App Check recognizes valid requests.
You can generate an app check token in the client and verify the token in the server using firebase admin SDK. Here is the firebase documentation for the same
Firebase enable App check enforcement documentation teaches you that to validate the caller from your function you just need to check the context.app then gives you an example like this
exports.EXAMPLE = functions.https.onCall((data, context) => {});
https://firebase.google.com/docs/app-check/cloud-functions?authuser=0
But when you are deploying your function in the google cloud dashboard, you select HTTP FUNCTION -> nodejs 14 -> then you are directed to code like this
/**
* Responds to any HTTP request.
*
* #param {!express:Request} req HTTP request context.
* #param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
My question when I saw this was: "How am i going to get a context if I only have request/response"
The answer is simple. YOU MUST SWITCH THE CONSTRUCTORS
You must re-write your function in a way that instead of dealing with req/res like any express function you are dealing with context/data
http functions are different of callable functions (the ones that deals with context/data)
IT IS SIMILAR BUT NOT EXACTLY EQUAL AND SOME MODIFICATIONS WILL BE NECESSARY.
mainly if your function deals with async stuff and have a delayed response you are going to need to rewrite many stuff
check this tutorial
https://firebase.google.com/docs/functions/callable

excel4node fetch request with next.js api routes not triggering download

I am generating an excel file and want it to be downloaded for the client by triggering an API route using the Next.js framework. I am having trouble triggering the download by using fetch. The download can be triggered by window.open(//urlhere, '_self') but the API call using fetch gives this response on request:
API resolved without sending a response for /api/download?Students= this may result in stalled requests.
The excel4node documentation says we can send an excel document through an API like this:
// sends Excel file to web client requesting the / route
// server will respond with 500 error if excel workbook cannot be generated
var express = require('express');
var app = express();
app.get('/', function(req, res) {
wb.write('ExcelFile.xlsx', res);
});
app.listen(3000, function() {
console.log('Example app listening on port 3000!');
});
Here is my backend download.js which lives in pages/api/:
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import Link from "next/link";
import getPartners from "../../components/main";
import excel from "excel4node";
export default function handler(req, res) {
const students = req.query.Students.split(",");
const partners = JSON.stringify(getPartners(students));
let workbook = createExcelList(partners);
workbook.write("PartnerList.xlsx", res);
}
const createExcelList = (partnersJSON) => {
const workbook = new excel.Workbook();
const partnersObject = JSON.parse(partnersJSON);
/* Using excel4node a workbook is generated formatted the way I want */
return workbook;
};
export const config = {
api: {
bodyParser: true,
},
};
And here is the function that is triggered on a button press in the front end.
const makePartners = async () => {
let queryStudents = studentList.join(",");
const url = "http://localhost:3000/api/download?Students=" + queryStudents;
if (studentList.length !== 0) {
try {
const res = await fetch(url, {
headers: {
"Content-Type":
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
},
});
console.log(res);
} catch (e) {
console.log(e);
}
}
};
Which does not trigger the download. But using window.open(url, '_self) does. So, I can trigger the download by changing the function to the following. However I don't think this is the correct way of doing things and would like to be able to understand how to use fetch correctly.
const makePartners = () => {
let queryStudents = studentList.join(",");
const url = "http://localhost:3000/api/download?Students=" + queryStudents;
if (studentList.length !== 0) {
window.open(url, "_Self");
}
};
I am not sure if this is a Next.js issue or not. Does anyone have any insight? Any help would be appreciated.

GET Request query always empty

I have wrote a function to check whether an email is unique or not within a collection. The issue, is that I have a GET request hooked onto this function, but the function's req.query is always empty.
My request looks like this: us-central1/users?email=mymail#test.com
I've tried doing this without Express, then I added Express, the same issue occurs.
Complete code: (deploying locally with npm run deploy)
const cors = require('cors');
const app = require('express')();
app.use(cors({ origin: true }));
initializeApp();
const fireStore = firestore();
const checkUserName = (req: any, res: any) => {
if (req.method !== 'GET') {
return res.status(405).send(`${req.method} is not allowed`);
}
console.log(JSON.stringify(req.query));
if (!req.query.hasOwnProperty('email')) {
return res.status(400).send('Email not provided');
}
const email = req.query.email;
if (email.trim().length === 0) {
return res.status(400).send('Invalid email address');
}
fireStore
.collection('users')
.doc(email)
.get()
.then((doc: any) => {
return res.status(200).send(doc);
})
.catch((error: any) => console.log(error));
};
app.get('/', checkUserName);
exports.users = functions.https.onRequest(app);

my http request won't work, angular 2

I am using a MEAN stack
I have successfully served a simple JSON object {"message":"hello"} sent with an express get and res.send function that appears in my web browser if I go to the route
also on my angular 2 front end I have an http.request() that works fine if I put a JSON test api url but if I put my route url to my simple JSON then I don't get a response. Any idea what the reason might be?
my angular 2 component.ts:
makeRequest(): void {
this.loading = true;
this.http.request('myurl/members')
.subscribe((res: Response) => {
this.data = res.json();
this.loading = false;
});
}
my server.js express:
// Get dependencies
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
var mongojs = require('mongojs');
var db = mongojs('sangha',['members']);
const app = express();
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Set port
const port ='80';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, () => console.log(`running on port ${port}`));
/*db methods
db.members.insert({"firstname":"Josh"});
db.members.findAndModify({
query: {lastname: ''},
update: {$set: {firstname: ''}},
new: true
}, function (err, doc, lastErrorObject){
//?
});
db.members.find(function(err,docs){
console.log("members collection: "+docs;
});
*/
/*submit on login page, first check the username doesn't already exists, then
db.members.insert*/
//app.post('/members',function(req,res)
app.get('/members',function(req,res){
res.send({"message":"hello"});
});
//this catch all must come after all route definitions
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});

Resources