I have an overloaded fetch function on an Angular service 'PostSvc'
if a user is provided as an argument the idea is to only return that users posts. Otherwise fetch all posts from the database....
The user is an 'object' passed from the post.ctrl.js with the following keys
{
username: $scope.currentUser,
body: $scope.postBody,
user_id: $scope.currentUser._id
}
this is giving me the _id field mongodb/mongoose generate as expected
console.log($scope.currentUser._id)
Here's the Mongoose Post model:
var db = require('../db')
var Post = db.model('Post', {
username : { type: String, required: true },
body : { type: String, required: true },
user_id: { type: String, required: true },
date : { type: String, required: true, default: Date.now },
})
module.exports = Post
Here's a snippet from the server.js file assigning the router:
app.use("/api/posts", require("./controllers/api/posts"))
Here's the Express './controllers/api/post.js' Router:
var Post = require('../../models/post')
var router = require('express').Router()
var websockets = require('../../websockets')
// this route works just fine
// returns All posts from the db
//
router.get("/", function(req, res, next) {
// find all posts from db
//
Post.find()
.sort("-date")
.exec(function(err, posts) {
if (err) { return next(err) }
res.json(posts)
next()
})
})
the probelem....
router.get("/:user_id", function(req, res, next) {
var query = {}
// these messages aren't being logged to console
// so there's no way the route is being used
console.log("from the get 'api/posts' method" )
console.dir(req.params.user_id)
if (req.params.user_id) {
query = { user_id: req.params.user_id } // sent from posts.svc.js
}
// this query is not executing properly
// I have no access to the `req.params.user_id`
//
Post.find({ user_id: req.params.user_id })
.sort("-date")
.exec(function(err, posts) {
if (err) { return next(err) }
res.json(posts)
next()
})
})
router.post("/", function(req, res, next) {
var post = new Post({ body: req.body.body })
if (!req.auth) { return res.sendStatus(401) }
post.username = req.auth.username
post.user_id = req.body.user_id
post.save(function(err, post) {
if (err) { return next(err) }
websockets.broadcast("new_post", post)
res.status(201).json(post)
})
})
module.exports = router
And last but not least here is the Angular Service that sends the initial 'GET' request to the 'server.js' -> './controllers/api/posts.js' and awaits the response:
angular.module("app").service('PostsSvc', function($http) {
this.fetch = function(user) {
var credentials = {}
if (user) {
credentials = user
// checkpoint
//
console.dir("from the fetch function " + credentials._id)
// only return authencated users posts
return $http.get("/api/posts", {
params: {
user_id: credentials._id // to the posts.js router
}
})
// return all posts otherwise
} else { return $http.get("/api/posts") }
}
this.create = function(post) {
return $http.post("/api/posts", post)
}
})
I have being in this same trouble with the router.get in express. The body is empty. I finally turned to use instead a router.post() which worked perfectly for me, as long as you also call the api with a post request whit angular.
Related
So I have something like this in one of my controllers:
module.exports.authToken = (req, res, next) => {
const token = req.cookies.jwt;
//console.log(token);
if (!token) {
return res.sendStatus(403);
}
try {
const data = jwt.verify(token, "secret token");
console.log(data);
req.userId = data.id;
return next();
} catch {
return res.sendStatus(403);
}
};
and it's called by a route:
router.get("/protected", authController.authToken, (req, res) => {
return res.json({ user: { id: req.userId, role: req.userRole } });
});
and I want to get a JSON response of that route in one of my other controllers. I tried some things but none of it worked.
What I would do is abstract the response out to a function for re-use:
// the function will just return the data without writing it to the response
function protectedRoute(req) {
return {user: {id: req.userId, role: req.userRole}};
}
router.get("/protected", authController.authToken, (req, res) => {
// in the actual handler you can return the response
return res.json(protectedRoute(req));
});
// make sure the middleware is still being run
router.get("/other_route", authController.authToken, (req, res) => {
// use the same function to get the response from /protected
const protectedResponse = protectedRoute(req);
// do stuff with it
});
Trying to implement the Passport-jwt strategy, I've got it working if I use a string as a 'secret', but I'm struggling to convert it to use a public/private key pair. I've probably made a simple mistake with the keys, but I don't understand what that is.
The login route provides me with a signed token with the pub/priv keys, but is always 'unauthorised' when I try the '/auth/test' route (whereas with the string secret is works)
The code below works, with the non-working code for the pub/priv key code highlighted/commented out.
Any help or comments appreciated!
./controllers/auth.js
exports.login = (req, res, next) => {
(async() => {
try {
const user = await User.findOne({ where: {email: req.body.email} });
if(!user) {
res.status(401).json({ success: false, message: "Bad Username/Password" });
}
const isValid = await bcrypt.compare(req.body.password, user.hashedPassword);
if(isValid) {
const tokenObject = utils.issueJWT(user);
res.status(200).json({ success: true, token: tokenObject.token, expiresIn: tokenObject.expires});
} else {
res.status(401).json({ success: false, message: "Bad Username/Password" });
}
} catch(err) {
next(err);
}
})();
};
./config/passport.js
...
const User = require('../models/user');
// ***** Not working
// const pathToKey = path.join(__dirname, '../../../.ssh/', 'jennings.pub');
// const PUB_KEY = fs.readFileSync(pathToKey, 'utf-8');
// *****
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secret',
// ***** Not working
// secretOrKey: PUB_KEY,
// algorithms: ['RS256']
// *****
}
function initialize(passport) {
const authenticateUser = async(jwt_payload, done) => {
let user;
try {
user = await User.findOne({
where: { id: jwt_payload.sub }
});
} catch(e) {
return done(e, false);
}
// No user found
if(!user) {
return done(null, false);
}
// User found
return done(null, user);
};
passport.use(new JwtStrategy(options, authenticateUser));
}
module.exports = initialize;
./util/utils.js
// ***** Not working
// const pathToKey = path.join(__dirname, '../../../.ssh/', 'jennings');
// const PRIV_KEY = fs.readFileSync(pathToKey, 'utf-8');
// *****
exports.issueJWT = (user) => {
const id = user.id;
const expiresIn = '1h';
const payload = {
sub: id,
iat: Date.now()
};
const signedToken = jwt.sign(payload, 'secret', { expiresIn });
// ***** Not working
// const signedToken = jwt.sign(payload, 'secret', { expiresIn, algorithm: 'RS256'});
// *****
return {
token: "" + signedToken,
expires: expiresIn
}
};
The test route
router.get('/test', passport.authenticate('jwt', { session: false }), (req, res, next) => {
res.status(200).json({ success: true, message: 'get in!' });
});
So I found a solution, based off of two other links:
The first here of an identical problem suggesting that the keys have to be in .pem format (but suggesting using an external library),
and here, which tells you to run ssh-keygen -f id_rsa.pub -m 'PEM' -e > id_rsa.pem on the public key to convert it to open-ssl compatible format (the private key is already in .pem format)
That worked for me
I have a simple ExpressJS/Node backend that contains a MongoDB database for which I use mongoose to interact. I can add objects to the db based on the UserSchema:
const userSchema = mongoose.Schema({
email : {
type: String,
required: true,
trim: true,
unique: 1
},
password : {
type: String,
required: true,
minlength: 5
},
name : {
type: String,
required: true,
maxlength: 30
},
lastname : {
type: String,
required: true,
maxlength: 30
},
cart : {
type : Array,
default: []
},
history : {
type: Array,
default: []
},
role : {
type: Number,
default : 0
},
token : {
type: String
}
});
From the express Server, I can register and add a new user to the DB and I know this works
Server.js
//========================================
// Register User
//========================================
app.post('/api/users/register', (req, res) => {
//create new User
const user = new User(req.body);
//save user
user.save((err, doc) => {
if(err)
return res.json({success: false, err});
res.status(200).json({
success : true,
userdata: doc
});
});
})
In User.js
//========================================
// SAVE in DB
//========================================
const User = mongoose.model('User', userSchema);
Now when I want to login, operation where I need to check the email and password match I encounter a problem when everything is fine and I want to add the JWT to the object all is good until it gets to the save method, there nothing happens and it doesn't respond anymore. It's like it goes in an infinite loop. I get error when something is wrong, but on the positive case, it disappears and sends no response, to either mongo, node, debug anything.
Server.js
app.post('/api/users/login', (req, res) => {
//find the email for the user
User.findOne({'email' : req.body.email} , (err, user) =>{
if(!user)
return res.json({loginSuccess : false, message : 'Authentication failed, email not found'});
//check the password
user.comparePassword(req.body.password, (error, isMatch) => {
if(!isMatch)
return res.json({loginSuccess : false, message : 'Wrong password'});
//generate token
user.generateToken((err, user) => {
if(err)
return res.status(400).send(err);
//store token as a cookie
res.cookie('w_auth', user.token).status(200).json({
loginSuccess : true
})
})
})
})
})
User.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const SALT_I = 10;
require('dotenv').config();
//========================================
// User Login
//========================================
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(error, isMatch){
if(error)
return cb(error);
cb(null, isMatch);
})
}
userSchema.methods.generateToken = function (cb) {
var user = this;
var token = jwt.sign(user._id.toHexString(),process.env.SECRET)
user.token = token;
user.markModified('anything');
user.save(function(err,user){
if(err) return cb(err);
cb(null,user);
})
}
I get no more feedback in node console, debug, Mongo or even Postmen(I can wait here for minutes ) after user.save(...). I know it gets the good user and everything but I don't really know where to get from here. Also in Mongo I see no field for the token, I initially add an object with no token, can this affect everything? Is there another procedure to update an existing object in the collection?
In case GitHub is needed to see the code: Link
Indeed it's really strange, couldn't really debug what's wrong with this 'save' method. As a workaround, however, this one seems to work fine:
userSchema.methods.generateToken = function (cb) {
var user = this;
var token = jwt.sign(user._id.toHexString(), "mystupidsecret");
console.log("in generateToken");
console.log(user);
user.token = token;
console.log(user.token);
var email = user.email;
//save token
User.updateOne({ _id: user._id }, { $set: { token: token } }, function(err, user){
if(err) {
console.log(err);
return cb(err);
}
cb(null, user);
// this one is for debug only!
User.findOne({'email' : email} , (err, user) =>{
console.log("After update: ", user)
});
});
console.log('done');
}
It yields the following:
After update: { cart: [],
history: [],
role: 0,
_id: 5f3e48f09c7edc3f1c24a860,
email: 'abc233#wp.pl',
password:
'$2b$10$iDeeehLOzbQi3dawqW8Lg.HPOvcRBDIS/YD9D1EmqBOH9Be31WpX2',
name: 'ABCDEFGH',
lastname: 'Doeasdasdas',
__v: 0,
token:
'eyJhbGciOiJIUzI1NiJ9.NWYzZTQ4ZjA5YzdlZGMzZjFjMjRhODYw.aH9tCMbIK9t3CReiQg3Azln9Ca8xS7W0xL3qCMOKniY' }
I am making an iOS project which uses Stripe. I am using a STPCustomerContext and the parameter to create an instance is an object of MainAPI below. When I create the instance, it automatically calls createCustomerKey() but an error (404) is throwing. The URL is "http://localhost:1337/ephemeral_keys" and I believe that is what I have everywhere but yet it is throwing a 404. Here is the code for MainAPI.swift, index.js, & api.js.
The code is:
MainAPI.swift
class MainAPI:NSObject, STPEphemeralKeyProvider {
// override init(){}
static let shared = MainAPI()
var baseURLString = Constants.BASE_URL
// MARK: STPEphemeralKeyProvider
enum CustomerKeyError: Error {
case missingBaseURL
case invalidResponse
}
func createCustomerKey(withAPIVersion apiVersion: String, completion: #escaping STPJSONResponseCompletionBlock) {
// the request
func request(id: String) {
print("creating a eph key request with customerId: \(id)") // good
let url = self.baseURLString.appending("/ephemeral_keys")
Alamofire.request(url, method: .post, parameters: [
"api_version": apiVersion,
"customerId": id
])
.validate(statusCode: 200..<300)
.responseJSON { responseJSON in
switch responseJSON.result {
case .success(let json):
print("created customer ephemeral key!")
completion(json as? [String: AnyObject], nil)
case .failure(let error):
print("could not customer ephemeral key!\n Error info: ")
print(error.localizedDescription)
completion(nil, error)
}
}
}
print("attempting to create customer ephemeral key . . .(createCustomerKey())")
let customerId = . . . // get customer id
request(id: costumerId) // this passes on the CORRECT customerId each time
}
}
api.js
var express = require('express')
var router = express.Router()
var stripe_key = process.env.STRIPE_KEY || "sk_test_myTestKey"
var stripe = require('stripe')(stripe_key);
var request = require("request-promise-native")
//API
router.get('/', function (req, res) {
res.status(200).send(JSON.stringify({ message: 'API Gateway', success: true, error: null }));
}) // Just for testing, just for error-handling
//1. Create a customer account
router.post('/new_customer', function (req, res) {
console.log("Creating new customer account...")
var body = req.body
stripe.customers.create({ email: body.email, })
.then((customer) => {
console.log(customer)
// Send customerId -> Save this for later use
res.status(200).send(JSON.stringify({ success: true, error: null, customerId: customer.id }));
})
.catch((err) => {
console.log(err)
res.status(400).send(JSON.stringify({ success: false, error: err }))
});
})
//2. Save Credit Card with token
router.post('/new_card', function (req, res) {
var customerId = req.body.customerId
var token = req.body.token
stripe.customers.update(customerId, { source: token })
.then((customer) => {
console.log(customer)
res.status(200).send(JSON.stringify({ success: true, error: null }));
})
.catch((err) => {
console.log(err)
res.status(400).send(JSON.stringify({ success: false, error: err }))
});
})
//3. Use customerId to post a charge
router.post('/new_charge', function (req, res) {
var customerId = req.body.customerId
var amount = req.body.amount
var source = req.body.source
stripe.charges.create({
amount: amount, //in cents
currency: "usd",
customer: customerId, //CUSTOMER_STRIPE_ACCOUNT_ID
source: source, // obtained with Stripe.js
}).then((charge) => {
res.status(200).send(JSON.stringify({ message: 'Sucess.', success: true, error: null }));
}).catch((error) =>{
res.status(400).send(JSON.stringify({ message: 'Error', success: false, error: error }));
})
})
// here is the error I am assuming
router.post('/ephemeral_keys', (req, res) => {
const stripe_version = req.body.api_version;
var customerId = req.body.customerId;
if (!stripe_version) {
res.status(400).end();
return;
}
console.log(stripe_version)
// This function assumes that some previous middleware has determined the
// correct customerId for the session and saved it on the request object.
stripe.ephemeralKeys.create(
{customer: customerId},
{stripe_version: stripe_version}
).then((key) => {
console.log("Ephemeral key: " + key)
res.status(200).json(key);
res.status(200).send(JSON.stringify({ message: 'AAAAhh', success: true, error: null }));
}).catch((err) => {
console.log("Ephemeral key error: " + err)
res.status(200).send(JSON.stringify({ message: 'ABBBBBB', success: true, error: null }));
res.status(500).end();
});
});
module.exports = router;
index.js
//Environment Vars
var uri = process.env.NODE_ENV || "development"
console.log(uri + " environment")
//Express App
var express = require('express');
var app = express();
//Api for reading http post request body in express
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
//Log Connections
app.use(function timeLog (req, res, next) {
console.log('incoming connection . . . ')
next()
})
//API middelware
var api = require('./api')
app.use('/api', api)
app.get('/', function (req, res) {
res.status(200).send(JSON.stringify({ message: 'Welcome!', success: true, error: null }));
});
//Create Server
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function () {
console.log('server running on port ' + port + '.');
});
When I create a STPCustomerContext (like this):
let apiKeyObject = MainAPI.shared
customerContext = STPCustomerContext(keyProvider: apiKeyObject)
The following error prints (not allowing the STPPaymentContext later to display):
Response status code was unacceptable: 404.
Please try with the below nodejs code, because syntax which your code is using might not be correct, I was using the same code as you, but later changed the implementation & deployed to firebase CLI
exports.createEphemeralKeys = functions.https.onRequest((req, res) => {
var api_version = req.body.api_version;
var customerId = req.body.customerId;
if (!api_version) {
res.status(400).end();
return;
}
stripe.ephemeralKeys.create(
{ customer: customerId },
{ stripe_version: api_version },
function(err, key) {
return res.send(key);
});
});
You might get below kind of logs.
{
id: 'ephkey_1BramAFjruqsvjkVQGdZLiV5',
object: 'ephemeral_key',
associated_objects: [ { type: 'customer', id: 'cus_CEPMtLbshv7EaP' } ],
created: 1517701830,
expires: 1517705430,
livemode: false,
secret: 'ek_test_YWNjdF8xQmxUb0FGanJ1cXN2amtWLHVPcUdMN3d4UEhncW1sQkNJYmlOdzhwUGdjVUxOd1Y'
}
For .swift file
Please Click here
Please have a look at https://www.youtube.com/watch?v=NdszUvzroxQ
I believe you need to use some remote server, instead of local server,
In my Swift file I am using .responseString instead of .responseJSON by this is I am getting success but the response is a HTML file of requesting Google Signin
I'm new to node.js and mongoose, and I'd appreciate it if someone could help me with the below error.
I make a put request via the following function (the point of the function is to "upvote" a forum post.
o.upvote = function(post) {
return $http.put('/posts/' + post._id + '/upvote')
.success(function(data){
post.upvotes += 1;
});
};
That in turn goes to my route:
index.js (my route)
router.put('/posts/:post/upvote', function(req, res, next) {
req.post.upvote(function(err, post){
if (err) { return next(err); }
res.json(post);
});
});
And below is my model
Posts.js
var mongoose = require('mongoose');
var PostSchema = new mongoose.Schema({
title: String,
link: String,
upvotes: {type: Number, default: 0},
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
mongoose.model('Post', PostSchema);
PostSchema.methods.upvote = function(cb) {
this.upvotes += 1;
this.save(cb);
};
In my index.js route, the below error is thrown on the line "req.post.upvote":
TypeError: req.post.upvote is not a function
req.post will not be set automatically. You need another middleware to set it, but most likely you want to get it from the DB with the parameter.
const Post = mongoose.model("Post");
router.put("/posts/:post/upvote", (req, res, next) => {
Post.findById(req.params.post, (err, post) => {
if (err) return next(err);
post.upvote((err, post) => {
if (err) return next(err);
res.json(post);
});
});
});
EDIT: You also need to set the methods before you create the schema in mongoose:
PostSchema.methods.upvote = function(cb) {
this.upvotes += 1;
this.save(cb);
};
mongoose.model('Post', PostSchema);