I want to run two same servers. And I want to upload a image from one to the other. These sources worked well but I felt that verifying a token is needed for security.
I will use the function createUploadToOther of settings.js to send image to the other server. I usually write a router like
router.post('/fromOther', verifyToken, function (req, res) {
But in this case, I don't know where to put that verifyToken. Could u let me know how to use a token with the multer header(?) in this case?
file.js
let express = require("express");
let router = express.Router();
let path = require('path');
let uploadDir = 'static'
let fs = require('fs');
const verifyToken = require('../libs/verifyToken')
const axios = require('axios')
const FormData = require('form-data')
let multer = require('multer');
let storageForSentFile = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, uploadDir);
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
})
let uploadForSentFile = multer({ storage: storageForSentFile })
router.post('/fromOther', uploadForSentFile.single('logo'), function (req, res) {
console.log("------file upload -------")
console.log(req.file)
res.json(req.file)
});
router.post('/toOther', uploadForSentFile.single('logo') , async function (req, res) {
let formData = new FormData()
formData.append('logo', fs.createReadStream(req.file.path), { knownLength: req.file.size })
const headers = {
...formData.getHeaders(),
"Content-Length": formData.getLengthSync()
};
try {
let result = await axios.post(
new URL('/file/fromOther', req.body.serverURL).href,
formData,
{headers }
)
res.status(200).json(result.data)
} catch (err) {
console.log('file/toOther err', err)
}
})
../libs/verifyToken.js
let jwt = require("jsonwebtoken");
const dotenv = require("dotenv");
function verifyToken(req, res, next) {
console.log("req.headers1 : ", req.headers);
let token = req.headers["authorization"];
if (!token)
return res.json({ status: 409, message: 'No authorization' })
jwt.verify(token, process.env.aSecretKey, function (err, decoded) {
if (err)
return res
.status(500)
.send({ auth: false, message: "Check your ID and password" });
console.log("decoded", decoded);
req.account = decoded.account;
req.idx = decoded.idx;
next();
});
}
module.exports = verifyToken;
settings.js
import axios from 'axios'
import { headers } from '../config/env'
export function createUploadToOther(data) {
return axios.post('/file/toOther', data, { headers })
}
Function verifyToken in router('/fromOther') checks just req.headers["authorization"], so I just added the function verifyToken to both router as argument(in fact don't need to add verifyToken to router('/toOther') but wanted to make it safer) and added the key "authorization" and the value as req.headers.authorization to router('/toOther'). Then it worked well, but I don't know this will be safe enough.
//(...)
router.post('/fromOther', verifyToken, uploadForSentFile.single('logo'), function (req, res) {
console.log("------file upload -------")
console.log(req.file)
res.json(req.file)
});
router.post('/toOther', verifyToken, uploadForSentFile.single('logo') , async function (req, res) {
let formData = new FormData()
formData.append('logo', fs.createReadStream(req.file.path), { knownLength: req.file.size })
const headers = {
...formData.getHeaders(),
"Content-Length": formData.getLengthSync(),
"authorization": req.headers.authorization
};
try {
let result = await axios.post(
new URL('/file/fromOther', req.body.serverURL).href,
formData,
{headers }
)
res.status(200).json(result.data)
} catch (err) {
console.log('file/toOther err', err)
}
})
//(...)
Related
I am getting img data and send this data to the server
console.log shows that data exists
const [fileData, setFileData] = useState("");
console.log("fileData:", fileData);
const getFile = (e: any) => {
setFileData(e.target.files[0]);
};
const uploadFile = (e: any) => {
e.preventDefault();
const data = new FormData();
data.append("file", fileData);
axios({
method: "POST",
url: "http://localhost:5000/api/setImage",
data: data,
headers: {
"content-type": "multipart/form-data", // do not forget this
},
}).then((res) => {
alert(res.data.message);
});
};
server endpoint
router.post("/setImage", userController.setImage);
async setImage(req, res, next) {
try {
let uploadFile = req.body;
console.log(uploadFile);
} catch (e) {
next(e);
}
}
console.log shows empty object but I'm waiting img data
Try using multer with fs and tempy.
router.post("/setImage", multer({ dest: tempy.file() }).single("file"), async (req, res, next) => {
if (!req.file) return
fs.readFile(req.file.path, function (err, filedata) {
if (!req.file) return
// Here you should get your expected data in filedata variable
})
})
I have created an auth.js middleware with fastify and prisma but I don't know how to insert it in my route. Here are some examples
const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = (request, reply) => {
try {
const token = request.headers.authorization.split(" ")[1];
const decodedToken = jwt.verify(token, process.env.SECRET_TOKEN);
request.token = decodedToken;
} catch (error) {
reply.status(401).send({
message: "Vous êtes pas authentifié",
});
}
};
const profilCtrl = require("../../controller/user");
const auth = require("../../middleware/auth");
async function routes(fastify) {
fastify.get("/profil/:id", profilCtrl.profile);
}
module.exports = routes;
You can add your auth function as a preHandler hook like this:
fastify.addHook('preHandler', (request, reply, done) => {
// some code
done()
})
or like this:
fastify.route({
method: 'GET',
url: '/profil/:id',
preHandler: fastify.auth([fastify.yourMiddleware]),
handler: (req, reply) => { ... }
})
Looking at your code I'm not totally clear on if it represents multiple files or what exactly is going on. You might want to break it up into separate blocks of code with file names to clarify your question.
The uploaded file is saved in the destination, but I can't access it in the express route.
Why might this be happening? It makes no sense to me...
EDIT: What I've noticed is that the console.log sometimes works, and sometimes doesn't... This is even weirder. If I upload a tiny file, it always logs. For larger ones, it randomly decides when to log. I wonder what the problem might be.
Client
async function uploadFile(file) {
console.log("file", file);
let formData = new FormData();
formData.append("file", file);
formData.append("recordUid", recordUid);
formData.append("fieldUid", fieldUid);
await fetchPostFile("/api/files", formData);
}
export async function fetchPostFile(url, formData) {
try {
let result = await (
await fetch(url, {
method: "POST",
withCredentials: true,
credentials: "include",
headers: {
Authorization: localStorage.getItem("token"),
},
body: formData,
})
).json();
return result;
} catch (err) {
return err;
}
}
Server
const express = require("express");
const router = express.Router();
const path = require("path");
const fs = require("fs");
const multer = require("multer");
const { getUidForTable } = require(`../utils.js`);
let filesFolderPath = path.join(__dirname, "../../../files/");
const storage = multer.diskStorage({
destination: filesFolderPath,
filename: async (req, file, cb) => {
cb(null, await getUidForTable("recordDataFile", 20));
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 1024 * 1024 * 10 }, // 10 mb
});
router.post("/api/files", upload.single("file"), async (req, res, next) => {
try {
console.log(req.file, req.body); // <------------ NOTHING IS LOGGED
res.status(200).send({ success: true });
} catch (err) {
next(err);
} finally {
req.connection.release();
}
});
After I define a cookie in an express cookie session, I can log it to the console with ease. However, when I attempt to access this cookie in another route of my application, it returns 'undefined'.
Setting the cookie:
router.get('/callback', catchAsync(async (req, res) => {
console.log("in /callback");
if (!req.query.code) throw new Error('NoCodeProvided');
const code = req.query.code;
const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
var response = await fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`,
{
method: 'POST',
headers: {
Authorization: `Basic ${creds}`,
},
});
var json = await response.json();
req.session.token = json.access_token
console.log(req.session.token)
>>> RETURNS THE TOKEN CORRECTLY <<<
Attempting to access the cookie in another route:
router.get('/loggedin', catchAsync(async (req, res) => {
console.log("/loggedin");
console.log("token: " + req.session.token);
>>> RETURNS 'token: undefined' <<<
In the first router.get('/callback'..) the catchAsync() function is not declared globally. It just handle this specific route, and doesn't really require a name.
You should wrap this function inside a middleware or create a function which is available globally, I don't know what is the goal but here is the 2 option.
Option 1 initiate the functionality as a middleware. The behaviour is depends on where you place it!!!! Maybe in that case doesn't fully makes sense, but you can play around, but I think you will get it.
// if you put before your router initiation it is going to have effect on all of the routes
app.use(async(req, res, next) => {
if (!req.query.code) throw new Error('NoCodeProvided');
const code = req.query.code;
const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
var response = await fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`,
{
method: 'POST',
headers: {
Authorization: `Basic ${creds}`,
},
});
var json = await response.json();
req.session.token = json.access_token
console.log(req.session.token)
//
// and you can do whatever want to do
// but have to call next
//
next()
})
// and your router looks like
router.get('/callback', (req, res) => {
// do what have to do
})
Option 2 - declare the middleware and use where you want
// defining this middleware somewhere in the code
const catchAsync = async(req, res, next) => {
if (!req.query.code) throw new Error('NoCodeProvided');
const code = req.query.code;
const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
var response = await fetch(`https://discordapp.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`,
{
method: 'POST',
headers: {
Authorization: `Basic ${creds}`,
},
});
var json = await response.json();
req.session.token = json.access_token
console.log(req.session.token)
//
// and you can do whatever want to do
// but have to call next
//
next()
}
router.get('/callback', catchAsync, (req, res) => {
// do what have to do
})
router.get('/loggedin', catchAsync, (req, res) => {
// do what have to do
})
Don't upload photos to the server, how to solve this problem?
on the page index.ejs a photo gallery should be generated from the added entries. The entry contains a photo. The entry is added, but the photo doesn't load.
project (GitHub)
app/routes.js:
var upload = multer({
storage: storage,
limits: {fileSize: 7},
fileFilter: function (req, file, cd) {
checkFileType(file, cd);
}
}).single('filePhoto');
function checkFiletType(file, cd) {
const fileTypes = /jpeg|jpg/;
const extname = fileTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = fileTypes.test(file.mimetype);
if (extname && mimetype) {
return cd(null, true);
} else {
cd('Error: only JPEG or JPG!')
}
var Photo = require('../app/models/photo');
module.exports = function (app, passport) {
app.get('/', function (req, res,next) {
Photo.find({}, function (error, photos) {
var photoList = '';
res.render('index.ejs', {photoList: photos});
});
});
}
app.post('/addPhoto', function (req, res, next) {
next();
}, function (req, res) {
var newPhoto = new Photo(req.body);
newPhoto.save().then(function (response) {
console.log('here', response);
res.status(200).json({code: 200, message: 'OK'});
}).catch(function (error) {
console.error('new photo error', error);
});
},function (req, res) {
Photo.find({}, function (error, photos) {
res.send('index.ejs', {
photoList: photos
});
});
});
};
You need to pass your upload var as middleware to your upload route.
Here is a snippet from how I have done it previously:
// Route:
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
router.post('/upload', upload.single('photo'), ImageController.upload);
// Image Controller:
upload(req, res){
console.log("file", req.file)
}
When I post my image, I make sure I call it photo to match the key word I used in my multer middleware:
So I create my form data like so:
const formData = new FormData()
formData.append('photo', {
uri: data.uri,
type: 'image/jpeg',
});
axios.post(`${SERVER}/images/upload`,
formData: formData,
{ headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => console.log("response", response))
.catch(err => console.log('err', err))