-1

I'm trying to send a base64 encoded jpg file to the nodejs server. I get a generic CORS error 'Multi-origin request blocked (cross-origin): the source matching criterion does not allow the remote resource to be read from http: // localhost: 8080 / uploadCarImage? Image = data: image / jpeg; base64. .. 'also inspecting the browser console I see a further error' 404 Bad Request '. The other http calls to the server work properly. How do I solve these errors? Thank you!

UPDATE:The errors screenshoot console browser console

Here is the code.

sell-new-car.component.ts:

import { Component, OnInit } from '@angular/core';
import * as _ from 'lodash';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { CarUploadService } from '../services/car-upload.service';
import { AuthenticationService } from '../services/authentication.service';

@Component({
  selector: 'app-sell-new-car',
  templateUrl: './sell-new-car.component.html',
  styleUrls: ['./sell-new-car.component.css']
})
export class SellNewCarComponent implements OnInit {

  imageError: string[] = [null, null, null];
  isImageSaved: boolean[] = [false, false, false];
  cardImageBase64: string[] = [null, null, null];
  imgBase64Path = [null, null, null];
  imageUrl: string[] = [null, null, null];

  step:boolean[] = [true, false, false, false, false];
  uploading:boolean = false;

  // Size Filter Bytes
  max_size = 1048576; // 1MB
  allowed_types = ['image/png', 'image/jpeg'];
  height = 300;
  width = 300;

  detailsForm: FormGroup;
  carId: number;
  brand: any;
  model: any;
  userId: number;

  constructor(private formBuilder: FormBuilder, private carUploadService: CarUploadService, private authenticationService:AuthenticationService) { }

  ngOnInit() {

    this.detailsForm = this.formBuilder.group({
      brand: ['', Validators.required],
      model: ['', Validators.required],
    });

  }

  // convenience getter for easy access to form fields
  get f() { return this.detailsForm.controls; }

  fileChangeEvent(fileInput: any, formN:number) {

    this.imageError[formN] = null;
    this.cardImageBase64[formN] = null;
    this.isImageSaved[formN] = false;

    if (fileInput.target.files && fileInput.target.files[0]) {

      if (fileInput.target.files[0].size > this.max_size) {
        //this.imageError = 'Maximum size allowed is ' + max_size / 1000000 + 'MB';
        this.imageError[formN] = 'Maximum size allowed is 1 MB';

        return false;
      }

      if (!_.includes(this.allowed_types, fileInput.target.files[0].type)) {
        this.imageError[formN] = 'Only Images are allowed ( JPG | PNG )';

        return false;
      }

      const reader = new FileReader();
      reader.onload = (e: any) => {
        const image = new Image();
        image.src = e.target.result;
        image.onload = rs => {
          const img_height = rs.currentTarget['height'];
          const img_width = rs.currentTarget['width'];

            if (img_height != this.height || img_width != this.width) {
              this.imageError[formN] = 'Dimentions allowed ' + this.height + '*' + this.width + 'px';

              return false;
            } else {
              let me = this;
              let reader2 = new FileReader();
              reader2.readAsDataURL(fileInput.target.files[0]);
              reader2.onload = function () {
                me.imgBase64Path[formN]= reader2.result;
              }
              //this.imgBase64Path[formN] = btoa(e.target.result);
              this.cardImageBase64[formN] = e.target.result;
              this.isImageSaved[formN] = true;
              this.imageUrl[formN] = fileInput.target.files[0].name;
              console.log('filename='+this.imageUrl[formN]);
              // this.previewImagePath = imgBase64Path;
            }
          };
      };

      reader.readAsDataURL(fileInput.target.files[0]);
    }
  }

  removeImage(formN) {
    this.cardImageBase64[formN] = null;
    this.isImageSaved[formN] = false;
  }

  saveDetails(){
    this.brand = this.detailsForm.controls['brand'].value;
    this.model = this.detailsForm.controls['model'].value;

    this.step[0] = false;
    this.step[1] = true;

  }

  upload(){

    this.uploading=true;
    this.userId = this.authenticationService.currentUserValue.id;

    this.carUploadService.uploadDetails(this.userId, this.model, this.brand).subscribe( data => {

      this.carId=data['carId'];

      this.uploadImages();

    });

  }

  uploadImages(){

    const imagePath = 'CarsImages/';

    for(let i=0;i<this.imageUrl.length;i++){
      this.carUploadService.uploadImage(this.imgBase64Path[i], i, imagePath+this.imageUrl[i], this.carId).subscribe( data =>{

        if(i==2){
          this.step[4] = false;
          this.step[5] = true;
        }

        //INSERIRE LA GESTIONE DEGLI ERRORI
      });
    }

  }

  nextStep(formN:number){

    if(formN == 0){
      this.step[1] = false;
      this.step[2] = true;
    }else if(formN == 1){
      this.step[2] = false;
      this.step[3] = true;
    }if(formN == 2){
      this.step[3] = false;
      this.step[4] = true;
      this.upload();
    }

  }
}

car-upload.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class CarUploadService {

  constructor(private http:HttpClient) { }

  headers = {
    headers: new HttpHeaders({
      'Content-Type' : 'application/json',
      'Accept': 'application/json'
    })
  };

  headersImageBase64 = {
    headers: new HttpHeaders({
      'Content-Type': 'multipart/form-data'
    })
  }

  uploadDetails(userId, model, brand){

    return this.http.post('http://localhost:8080/uploadCarDetails?userId=' + userId +'&model=' + model +'&brand=' + brand, this.headers);

  }

  uploadImage(image, imageN, imageUrl, carId){

    console.log('uploadCarImage');
    console.log('imageUrl='+imageUrl);

    return this.http.post('http://localhost:8080/uploadCarImage?image=' + image +'&imageN=' + imageN + '&imageUrl=' + imageUrl + '&carId=' + carId , this.headersImageBase64);

  }

}

server.js

var mysql = require('mysql');
var express = require('express');
var cors = require('cors');
const jwt = require('jsonwebtoken');
var sanitizer = require('sanitizer');
const fs = require("fs")
const fileUpload = require('express-fileupload');


var app = express();
app.use(cors());

// enable files upload
app.use(fileUpload({
    createParentPath: true
}));

var connection = mysql.createConnection({
    host: '127.0.0.1',
    user: 'andrea',
    password: 'password',
    database: 'cars_market_place'
});

try{

    connection.connect();

}catch(err){

    console.error("Error:"+err);

}

const RSA_PRIVATE_KEY = fs.readFileSync('./privateKEY.pem');
const passphrase = 'vivalafiga';

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

function LinkMysql(query) {

    return new Promise(function(resolve, reject) {

        connection.query(query, function(err, result) {

            if (err)
                console.error(err);

            resolve(result);

        });

    });

}  

app.route('/getCars').get(function(request, response){

    console.log("/getCars");

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    query = 'SELECT `cars`.`id`, `cars`.`model`, `cars`.`brand`, `cars`.`image1`, `cars`.`image2`, `cars`.`image3`, `users`.`id` AS userId, `users`.`username` FROM `cars`, `users` WHERE `users`.`id` = `cars`.`id_user`';

    LinkMysql(query).then(function(data) {

        response.writeHead(200, {'content-Type': 'text/plain; charset=utf-8'});
        console.table(data);
        response.end(JSON.stringify(data));

    });

});

app.route('/getCarFromId').get(function(request, response){

    console.log("/getCar");

    // Prevent xss
    carId = sanitizer.sanitize(request.query.carId);

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    query = 'SELECT `cars`.`id`, `cars`.`model`, `cars`.`brand`, `cars`.`image1`, `cars`.`image2`, `cars`.`image3`, `users`.`id` AS userId, `users`.`username` FROM `cars`, `users` WHERE `users`.`id` = `cars`.`id_user` AND `cars`.`id` = ' + carId;

    LinkMysql(query).then(function(data) {

        response.writeHead(200, {'content-Type': 'text/plain; charset=utf-8'});
        response.end(JSON.stringify(data));

    });

});
/*
app.route('/getCarFromModelBrand').get(function(request, response){

    console.log("/getCarFromModelBrand");

    // Prevent xss
    modelS = sanitizer.sanitize(request.query.model);
    brandS = sanitizer.sanitize(request.query.brand);

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    query = 'SELECT `cars`.`id` FROM `cars` WHERE `cars`.`model` = +' modelS + ' AND `cars.brand``cars`.`id_user` AND `cars`.`id` = ' + carId;

    LinkMysql(query).then(function(data) {

        response.writeHead(200, {'content-Type': 'text/plain; charset=utf-8'});
        response.end(JSON.stringify(data));

    });

});
*/
app.route('/getUserByUsername').get( function(request, response){

    console.log("/getUserByUsername");

    // Prevent xss
    var usernameS = sanitizer.sanitize(request.query.username);
    console.log("username="+usernameS);

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    query = 'SELECT * FROM `users` WHERE `users`.`username` = ' + connection.escape(usernameS);

    LinkMysql(query).then(function(data) {

        response.writeHead(200, {'content-Type': 'text/plain; charset=utf-8'});
        response.end(JSON.stringify(data));

    });

});

app.route('/login').post( function(request, response) { 

    console.log('/login');

    let username = request.query.username;
    let password = request.query.password;

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    if (username && password) {

        usernameS = sanitizer.sanitize(request.query.username);

        getUserByUsername(connection.escape(usernameS)).then( function(user){

            if (!user) {
                response.status(401).json({ msg: 'user not found', user: username });
            } else{

                if (user.password === password) {

                    jwt.defaul

                    const jwtBearerToken = jwt.sign({}, {key:RSA_PRIVATE_KEY, passphrase:passphrase}, {
                        algorithm: 'RS256',
                        expiresIn: 10000,
                    })

                    response.status(200).json({ msg: 'ok', idToken: jwtBearerToken, expiresIn:10000, 
                        user: {id:user.id, 
                            username:user.username,
                            password:'',
                            email:user.email,
                            firstname:user.firstname,
                            lastname:user.lastname,
                            token:''
                        } 
                    });

                    /*
                    response.json({ msg: 'ok', idToken: jwtBearerToken, expiresIn:3600, 
                        user: {id:user.id, 
                            username:user.username,
                            password:'',
                            email:user.email,
                            firstname:user.firstname,
                            lastname:user.lastname,
                            token:''
                        } 
                    });
    */
                } else {

                    response.status(401).json({ msg: 'Password is incorrect' });

                }

            }

        }).catch( (err) => {

            console.error(err);

        });

    }

});

app.route('/register').post( function(request, response) { 

    console.log('register');

    let username = request.query.username;
    let password = request.query.password;
    let firstname = request.query.firstname;
    let lastname = request.query.lastname;
    let email = request.query.email;

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    if (username && password && email) {

        // Prevent xss
        usernameS = sanitizer.sanitize(username);
        passwordS = sanitizer.sanitize(password);
        firstnameS = sanitizer.sanitize(firstname);
        lastnameS = sanitizer.sanitize(lastname);
        emailS = sanitizer.sanitize(email);

        getUserByUsername(usernameS).then( function(user){

            if (!user) {
                console.log("user not found:" + username);
                //inserisci nel database
                query = 'INSERT INTO `users` (`firstname`, `lastname`, `username`, `password`, `email`) ' +
                        'VALUES (' + connection.escape(firstnameS) + ', '
                        + connection.escape(lastnameS) + ', ' 
                        + connection.escape(usernameS) + ', ' 
                        + connection.escape(passwordS) + ',' 
                        + connection.escape(emailS) + ')';

                console.log('query='+query);

                connection.query(query, function(err, result) {

                    if (err)
                        console.error('error: ' + err);

                    response.status(200).json({msg:'registration success'});

                });


            }else{

                console.log("username taken:" + username);

                response.status(409).json({ msg: 'username taken' });

            }

        }).catch( (err) => {

            console.error(err);

        });

    }else{

        console.error('no data avaiable');

        response.status(409).json({ msg: 'no data avaiable' });

    }

});

app.route('/uploadCarDetails').post( function(request, response){

    console.log('uploadCarDetails');

    let userId = request.query.userId;
    let model = request.query.model;
    let brand = request.query.brand;

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    if (userId && model && brand) {

        // Prevent xss
        userIdS = sanitizer.sanitize(userId);
        modelS = sanitizer.sanitize(model);
        brandS = sanitizer.sanitize(brand);

        query = 'INSERT INTO `cars` (`id_user`, `model`, `brand`) ' +
                'VALUES (' + connection.escape(userIdS) + ', '
                + connection.escape(modelS) + ', ' 
                + connection.escape(brandS) + ')';

        console.log('query='+query);

        connection.query(query, function(err, result) {

            if(err){

                console.error('error: ' + err);

                response.status(409).json({msg:'error: ' + err});

            }else{

                query = 'SELECT `id` FROM `cars` WHERE (`model`=' + connection.escape(modelS) + ' AND `brand`=' + connection.escape(brandS) + ')';

                LinkMysql(query).then( result => {

                    var carId = result[0].id;
                    response.status(200).json({msg:'upload success', carId:carId});

                }).catch((err) => {

                    console.error('error: ' + err);

                    response.status(409).json({msg:'error: ' + err + '.check server log'});

                });

            }

        });

    }else{

        console.error('no data avaiable');

        response.status(409).json({ msg: 'no data avaiable' });

    }
});

app.route('/uploadCarImage').post( function(request, response){

    console.log('/uploadCarImage');

    let imageN = request.query.imageN || "";
    let image = request.query.image || "";
    let imageUrl = request.query.imageUrl || "";
    let carId = request.query.carId || "";

    console.log('imageN='+imageN);
    console.log('image='+image);
    console.log('imageUrl='+imageUrl);
    console.log('carId='+carId);

    response.setHeader("Access-Control-Allow-Origin", "*"); 
    response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    response.setHeader("X-Powered-By",' 3.2.1');
    response.setHeader("Content-Type", "application/json");

    if ( imageN && image && imageUrl && carId) {

        imageUrlS = sanitizer.sanitize(imageUrl);
        carIdS = sanitizer.sanitize(carId);

        console.log('imageUrlS='+imageUrlS);
        console.log('imageUrl='+imageUrl);

        query='';


        if(imageN==0){

            query = 'UPDATE `cars` SET `image1` = '+ connection.escape(imageUrlS) + ' WHERE `id` = ' + connection.escape(carIdS);

        }else if(imageN==1){

            query = 'UPDATE `cars` SET `image2` = '+ connection.escape(imageUrlS) + ' WHERE `id` = ' + connection.escape(carIdS);

        }else if(imageN==2){

            query = 'UPDATE `cars` SET `image3` = '+ connection.escape(imageUrlS) + ' WHERE `id` = ' + connection.escape(carIdS);

        }

        console.log('query='+query);

        connection.query(query, function(err, result) {

            if(err){

                console.error('error: ' + err);

                response.status(409).json({msg:'error: ' + err});

            }else{

                response.status(200).json({msg:'upload success'});

            }

        });

        //save image to disk
        try{

            if(!request.files) {

                response.status(409).json({msg:'no file avaiable to upload'});

            } else {
                //Use the name of the input field (i.e. "avatar") to retrieve the uploaded file
                let image = request.files.image;

                //Use the mv() method to place the file in upload directory (i.e. "uploads")
                image.mv('../src/assets/CarsImages/' + image.url);

                //send response
                response.status(200).json({msg:'upload success'});
            }

        }catch(error){

            console.error(error);
            response.status(409).jsno({msg:'error='+error+'. check server log'});

        }

    }else{

        console.error('no data avaiable');

        response.status(409).json({ msg: 'no data avaiable, check server log' });

    }
});

function getUserByUsername(username){

    return new Promise((resolve, reject) => {

        query = 'SELECT * FROM `users` WHERE `users`.`username` = ' + connection.escape(usernameS);

        LinkMysql(query).then(function(data) {

            resolve(data[0]);
            reject(null);

        }).catch((err)=> {

            console.error('Error:' + err);

        });

    });

}

app.listen(8080);
console.log('server listening on 8080');
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • have you tried binding the server on 0.0.0.0 with `var server = app.listen(8080, '0.0.0.0',onServerListening);` – Ozeta Feb 08 '20 at 18:50
  • Replace your `app.use(cors())` line with `app.options('*', cors())`. Without that, your server otherwise appears to not be handling OPTIONS requests as expected. See the docs at https://github.com/expressjs/cors#enabling-cors-pre-flight – sideshowbarker Feb 10 '20 at 02:30
  • @sideshowbarker thanks for reply, your suggestion doesen't work. in reference to the documentation you mentioned, I use POST and it is not required to enable 'CORS Pre-Flight' –  Feb 10 '20 at 08:24

1 Answers1

0

You can try to replace:

app.use(cors());

with

app.use(cors({
  origin: '*'
}));
TheOni
  • 810
  • 9
  • 26
  • 1
    @canerandagio can you please show us the full console output(both browser and nodejs server) so we can have some more info – TheOni Feb 09 '20 at 10:03
  • @canerandagio I think that the issue is caused by the base64 of the image sent as query param... you should implement the POST request as per standard inserting those information in request body and not as query string – TheOni Feb 09 '20 at 19:53
  • 1
    your suggestion to pass the image in the body was correct. Thanks –  Feb 10 '20 at 08:33