Firestore add auth to request - javascript

I am trying to figure out how to authenticate my request to firestore.
I am using https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY> for both which returns me an idToken of the user.
I do authentication on my routes which work but exposes my firestore still, thus me switching over to using security rules but I can't seem to authenticate any request.
I am using express to handle routes to firestore using this format locally:
GET http://localhost:5001/<PROJECT_ID>/us-central1/database/users/
Rules: allow read, write: if true;
GET https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users
content-type: application/json
Response: 200 (And I see all the documents)
Rules: allow read, write: if request.auth != null;
GET https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users
Authorization: Bearer {{idToken}}
content-type: application/json
Response: {
"error": {
"code": 403,
"message": "Missing or insufficient permissions.",
"status": "PERMISSION_DENIED"
}
}
MORE DETAILED INFO
The code below works, but with firebase other way of getting the data, it bypasses this and will only limit based on security rules.
index.ts
import * as functions from 'firebase-functions';
import * as express from 'express';
import * as cors from 'cors';
import isAuthenticated from './components/middleware/authenticated';
import isAuthorized from './components/middleware/authorized';
import users_all from './users/controllers/all';
const route = express();
route.use(cors({ origin: true }));
route.get('/users', isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'] }), users_all);
exports.database = functions.https.onRequest(route);
users_all
import { Request, Response } from "express";
import sentry from '../../components/reporting/sentry';
import Fireapp from '../../components/firebase/fireapp';
Fireapp
const all = async (req: Request, res: Response) => {
try {
let profiles: any = [];
/** Retrieve the exact document reference */
const reference = Fireapp.firestore().collection('users').get()
.then((documents: firebase.firestore.QuerySnapshot) => {
documents.docs.forEach((doc: firebase.firestore.DocumentData) => { profiles.push(doc.data()) });
return profiles;
});
return Promise.all([reference]).then((response: any) => {
res.status(200).send(profiles);
}).catch((error: any) => { throw error });
} catch (error) {
sentry(error, { service: '[GET ALL USER]', level: 'moderate', message: error.message });
res.status(400).send(error.message)
}
}
export default all;

Related

Struggling to find memory leak. NodeJS, Express, MongoDB

so I have a NodeJS with Express configured for API calls to get data from my backend Database.
Everything works great except there is a memory leak that I can't seem to solve no matter what I do. I have narrowed it down to a MongoDB fetch call, that grabs data from MongoDB.
Since the Data being sent is the same, and to avoid multiple requests to MongoDB, I created a top level variable that fetches that data so on a request it sends that, vs doing a fetch constantly as it would be 1000's of requests every minute.
I have also set the --max_old_space_size variable to 4096 and higher at 8192 and will eventually crash also.
Below is the fetch code.
//router get apis.js
import { Model } from '../../dbmodels/models.js';
let data = null;
// Bot interval
setInterval(async () => {
try {
data = await tokenModel.find({
$or: [
{ "currentRanks.minuteTokenRank": {$lt: 51} },
{ "currentRanks.fiveMinuteTokenRank": {$lt: 51} },
{ "currentRanks.fifteenMinuteTokenRank": {$lt: 51} },
{ "currentRanks.thirtyMinuteTokenRank": {$lt: 51} },
{ "currentRanks.hourlyTokenRank": {$lt: 51} },
{ "currentRanks.dailyTokenRank": {$lt: 51} },
{ "currentRanks.weeklyTokenRank": {$lt: 51} }
]
}).lean();
} catch (error) {
console.error(error);
return;
}
}, 45000);
export async function main(req, res) {
let dataRes = data;
try {
res.status(200).json(dataRes);
dataRes = null;
} catch {(err) => {
res.status(500).json({ message: err.message })
console.log('err', err.message)
}
}
//console.log('Get Top Data')
}
//main server.js file
import dotenv from "dotenv"
dotenv.config()
import express from 'express';
const app = express();
import { createServer } from 'https';
import { createServer as _createServer } from 'http';
import { readFileSync } from 'fs';
import compression from "compression";
import pkg from 'mongoose';
const { connect, connection } = pkg;
import cors from 'cors';
import auth from './utils/auth.js'
connect(process.env.DB_URL);
let mongoClient = connection;
mongoClient.on('error', (error) => console.error(error));
mongoClient.once('open', () => console.log(`Cncted to DB ${mongoClient.name}`));
app.use(compression());
app.use(cors({ origin: ['http://localhost:3000']}));
// Apis route
import apis from './apis/apis.js';
app.use('/api', auth, apis);
//listen both http & https
const httpServer = _createServer(app);
const httpsServer = createServer({
key: readFileSync('redacted.pem'),
cert: readFileSync('redacted.pem'),
}, app);
httpServer.listen(3000, () => console.log('Server Started port 3000'));
httpsServer.listen(3001, () => {
console.log('HTTPS Server running port 3001')
})
So looks like I was able to find the leak. It wasn't with any of the API's I posted. But a hidden one that I use or Web3. There is a known bug on the web3 package leaving connections open.
This is tied to the data I am retrieving above which is why it seemed to me like it was this API, but further troubleshooting found the real issue.
Here is the issue in case anyone uses web3 packages and runs into similar.
https://github.com/web3/web3.js/issues/3042#issuecomment-663622882

blocked by CORS policy Method PATCH is not allowed

im tryng build crud app using MERN stack,
method add and get not got blocked by cors,
but patch method got blocked by cors
alredy install cors module on my server
and still didnt work
routes
import express from 'express';
import { createPost, getPost, updatePost } from '../controllers/posts.js';
const router = express.Router();
router.get('/', getPost);
router.post('/', createPost);
router.patch('/:id', updatePost);
export default router;
server/controllers
export const updatePost = async (req, res) => {
const { id: _id } = req.params;
const post = req.body;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`no post with id ${id}`);
const updatedPost = postMessage.findByIdAndUpdate(_id, post, { new: true });
res.json(updatedPost);
};
client>src>api
import axios from 'axios';
const url = 'http://localhost:3001/posts';
export const fetchPosts = () => axios.get(url);
export const createPost = (newPost) => axios.post(url, newPost);
export const updatePost = (id, updatePost) =>
axios.patch(`${url}/${id}`, updatePost);
Certain CORS requests are considered ‘complex’ and require an initial OPTIONS request (called the “pre-flight request”)
If you are making requests other than GET/HEAD/POST (such as PATCH) you need to enable pre-flight request
Serverside add these lines
app.options('/posts/:id', cors()) // enable pre-flight request
Source - [ExpressJs Docs][1]
[1]: https://expressjs.com/en/resources/middleware/cors.html#:~:text=on%20port%2080%27)%0A%7D)-,Enabling%20CORS%20Pre%2DFlight,-Certain%20CORS%20requests

Send data between GraphQL Node.js server and React in Nx

I setup two projects, Node.js and React in Nx monorepo. I would like to use GraphQL for communication. Projects I'm running with command nx serve api(Node.js) and nx serve totodile (React). Problem is that React cannot access data from /graphql endpoint.
React is running on http://localhost:4200/.
Node.js is running on http://localhost:3333/.
Node.js part
According to GraphQL instructions for Node.js I run Node.js server. I have created two endpoints /api and /graphql.
import * as express from 'express';
import { graphqlHTTP } from 'express-graphql';
import { Message } from '#totodile/api-interfaces';
import { buildSchema } from 'graphql';
const app = express();
const greeting: Message = { message: 'Welcome to api!' };
app.get('/api', (req, res) => {
res.send(greeting);
});
app.use('/graphql', graphqlHTTP({
schema: buildSchema(`
type Query {
hello : String
}
`),
rootValue: {
hello: () => 'Hello world'
},
graphiql: true,
}));
const port = process.env.port || 3333;
const server = app.listen(port, () => {
console.log('Listening at http://localhost:' + port + '/api');
});
server.on('error', console.error);
In a result I am able to connect to http://localhost:3333/graphql and receive response. So graphql server is working well.
// graphql response
{
"data": {
"hello": "Hello world"
}
}
React part
Inside functional component I fetch with /api and /graphql. First one return valid data, but /graphql is returning 404, Cannot POST /graphql.
useEffect(() => {
fetch('/api') // successfully return data
.then((r) => r.json())
.then(setMessage);
fetch('/graphql', { // 404, no data
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({query: "{ hello }"})
})
.then(r => r.json())
.then(data => console.log('data returned:', data));
}, []);
I investigate that:
http://localhost:4200/api return valid data ("message": "Welcome to api!")
http://localhost:3333/api return valid data ("message": "Welcome to api!")
http://localhost:4200/graphql 404 no data
http://localhost:3333/graphql return valid data ("hello": "Hello world")
It must be something with ports.
I don't understand how /api is able to return any data. Why on both ports?
What should I do to share data from /graphql to react?
To fix issue there was 2 steps to do:
In React I should fetch from endpoint with port fetch('http://localhost:3333/graphql',(...))
In Node.js there is need to use cors library
import express from "express";
import cors from 'cors';
const app = express();
app.use(cors());
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
...

next.js app works fine in local but returns 500 internal server error on production

the problem i'm having is basically my app works fine in local but in production anywhere that i've used server side rendering returns 500 internal server error. the other parts of my site which are called normally like in useEffect or componentDidMount work completely fine, like my dashboard or authorization process works without a problem, but anywhere that i have used ssr returns 500.
Below is some examples of how i have handled my ssr pages.
index page:
import React from 'react';
import HomePage from '../components/homePage/index'
import { Api, GuestHeaders } from '../components/config'
const Home = (props) => {
return <HomePage {...props} />
}
export async function getServerSideProps() {
const Response = await Api.get(`/v1/index`, { headers: GuestHeaders })
return {
props: {
Detail: Response.data,
}
}
}
export default Home
here is my Api component:
import axios from 'axios';
const GuestHeaders = {
'Authorization': "",
'content-type': 'application/json'
}
const Api = axios.create({
baseURL: 'baseUrl'
})
export { Api, GuestHeaders };
here is my server.js:
// server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer((req, res) => {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
}).listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
and my next.config.js:
module.exports = {
basePath: '',
trailingSlash: false,
}

Post request in VueJs with undefined response

I am a beginner in VueJs and Expressjs. I am trying to make frontend side by Vuejs and backend by ExpressJs. I send a post request to the backend (expressJs) and :
1- Response is undefined
2- At the same time I can see 2 requests in chrome development tools. One is Option and another one is Post.
3- With postman there is no problem at all.
Here is the code of app.js in express
console.log('Server is running')
const express = require('express'),
bodyParser = require('body-parser'),
cors = require('cors'),
morgan = require('morgan');
app = new express();
//Setup middleware
app.use(cors());
app.use(morgan('combined'))
app.use(bodyParser.json())
app.post('/register', (req, res, next) => {
res.send({
message: `Hello ${req.body.email}! your user was registered!`
})
});
app.listen(8081);
And here is the code in VueJs :
// Api Setting
import axios from 'axios'
export const HTTP = axios.create({
baseURL: `http://localhost:8081`
});
// AuthenticationService
import { HTTP } from '../services/Api'
export default {
register(credentials) {
HTTP.post('register', credentials);
}
}
// Register Component
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
async register() {
const response = await AuthenticationService.register({
email: this.email,
password: this.password
});
console.log(response); // the value is undefined
}
}
};
I really don't know what I missed here that I get an undefined response and 2 requests at the same time. I appreciate any hint.
Whole code on github repo : here
Maybe. Authentication.register is not returning anything or more specifically a Promise which should be used to populate const response in the await call.
Try returning something like so: return HTTP.post('register', credentials); inside register.
For this to work though, HTTP.post('register', credentials) should also return something.
I use JSON.stringify to send the data, you are sending the objects directly, so
register(credentials) {
HTTP.post('register', credentials);
}
becomes
register(credentials) {
HTTP.post('register', JSON.stringify(credentials));
}

Categories