On my web site I stuck in the change password part.
I send an email to the user to change the password, on this link I pass a token on the URL to use is to find the user with findOne.
My problem is the following I was able to get the URL on the router.get but I cannot get it on router.post. I need too get it on router.post because I receive the password from the user on router.post.
Here is my code :
server.js
if(process.env.NODE_ENV !== 'production') {
const dotenv = require('dotenv')
dotenv.config();
}
const express = require('express')
const expressLayouts = require('express-ejs-layouts')
const passport = require('passport')
const flash = require('express-flash')
const session = require('express-session')
const dotenv = require('dotenv')
const app = express()
require('./passport-config')(passport);
const indexRouter = require('./routes/index')
const registerRouter = require('./routes/register')
const loginRouter = require('./routes/login')
const parentRouter = require('./routes/parent')
const animatorRouter = require('./routes/animator')
const confirmationRouter = require('./routes/confirmation')
const activateRouter = require('./routes/activate')
const cguRouter = require('./routes/cgu')
const confidentialiteRouter = require('./routes/confidentialite')
const lost_passwordRouter = require('./routes/lost_password')
const Change_passwordRouter = require('./routes/change_password')
app.set('view engine','ejs')
app.set('views', __dirname + '/views')
app.set('layout', 'layouts/layout')
app.use(expressLayouts)
app.use(express.static('public'))
app.use(express.json())
app.use(express.urlencoded({ extended : false }))
app.use(flash())
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
const mongoose = require('mongoose');
mongoose.connect(process.env.DATABASE_URL, {
useNewUrlParser: true, useUnifiedTopology: true}).then(()=>{
console.log('Successfully connected to the mongoDB Atlas!')
}).catch((error)=>{
console.log('impossible to connect to the mondoDB Atlas !')
console.error(error);
});
app.use('/', indexRouter)
app.use('/register', registerRouter)
app.use('/login', loginRouter)
app.use('/animator', animatorRouter)
app.use('/parent', parentRouter)
app.use('/confirmation', confirmationRouter)
app.use('/activate', activateRouter)
app.use('/cgu', cguRouter)
app.use('/confidentialite', confidentialiteRouter)
app.use('/lost_password', lost_passwordRouter)
app.use('/change_password',Change_passwordRouter)
app.listen(process.env.PORT || 3000)
change_password.js
const express = require('express')
const router = express.Router()
const Users = require('../models/register')
router.get('/:token', async (req, res) =>{
let {token} = req.params
console.log(token)
let user = await Users.findOne({resetPasswordToken: token})
user.save()
console.log(user)
res.render('change_password/change_password')
res.send(token)
})
router.post('/', async (req, res)=>{
let {token} = req.params
console.log(token)
// const user = await Users.findOne({ Users.resetPasswordToken })
// console.log(user)
// console.log(user)
// user.password = req.body.password
// await user.save()
})
module.exports = router
change_password.ejs
<form action="/change_password" method="POST">
<div>
<label for="password">New Password</label>
<input type="password" name="password" id="password" required>
</div>
<button type="submit">Login</button>
lost_password.js
const express = require('express')
const router = express.Router()
const Users = require('../models/register')
const nodemailer = require('nodemailer');
const flash = require('express-flash')
const jwt = require('jsonwebtoken')
const secret = require('crypto').randomBytes(64).toString('hex')
router.get('/', (req, res) =>{
res.render('lost_password/lost_password', {message : req.flash('success')})
})
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '',
pass: ''
}
});
router.post('/', async (req,res)=>{
const user = await Users.findOne({email: req.body.email})
if(!user) {
return res.status(401).json({
success: false,
message: "This email do not exist in our base"
})
}
user.resetPasswordToken = jwt.sign({ email: user.email}, secret, { expiresIn: '1h'})
user.save()
req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.')
console.log(user.resetPasswordToken)
const mailOptions = {
from: '',
to: user.email,
subject: 'Localhost activation link',
text: 'http://localhost:3000/change_password/'+ user.resetPasswordToken,
html:'link'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
res.redirect('/lost_password')
})
module.exports = router
lost_password.ejs
<h1>Lost Password</h1>
<form action="/lost_password" method="POST">
<div>
<label for="email">Indiquez votre email</label>
<input type="email" name="email" id="email" required>
</div>
<button type="submit">Register</button>
</form>
<%= message %>
Thank you for your help.
Just change your
router.post('/')
with router.post('/:token')
Related
Index.Js File:
const cookieSession = require("cookie-session");
const express = require("express");
const app = express();
const helmet = require("helmet");
const morgan = require("morgan");
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const userRoute = require("./routes/user")
const authRoute = require("./routes/auth")
dotenv.config();
//Mongoose Connect
mongoose.connect(process.env.MONGO_URL, {useNewUrlParser: true}, (err) =>
{
console.log("mongdb is connected");
});
//middleware
app.use(express.json());
app.use(helmet());
app.use(morgan("common"));
app.get("/", (req, res) => {
res.send("Welcome to home page");
})
app.use("/api/auth", authRoute);
app.use("/api/user", userRoute);
app.listen(5000,function(err)
{
if(err)
console.log("Server not connected")
console.log("Connnection is established");
})
Auth.Js File
const router = require("express").Router();
const User = require('../model/Users');
//REGISTER
router.get("/register", async (res,req)=> {
const user = await new User({
username: "gauravnegi",
password: "123456",
email: "gauravnegi#gmail.com",
});
await user.save();
res.send("ok");
});
module.exports = router;
Error:
return callback(new error_1.mongoservererror(res.writeerrors [0] ))
Full Error Snippet:
How to resolve above error?
Dear it is not a server side error it's a client side error b/c you have defined somewhere some field {unique:true} in your model! So you should wrap your function inside try-catch block for example
router.get("/register", async (res,req)=> {
try{
const user = await new User({
username: "gauravnegi",
password: "123456",
email: "gauravnegi#gmail.com",
});
await user.save();
res.send("ok");
}catch(error){
//check if it was a duplication error
if(error.code==11000) // show user that it is unique path
and handle other validation error
}
});
Working with Registration in a Site. For the register Form,Validation is done using mongoose models and trying to Use Flash to display the error message in the Form.
In my nodejs app it shows an error like:
TypeError: req.flash is not a function
I have installed connection-flash npm it is throwing an error like:
TypeError: req.flash is not a function at
E:\node-course\apnadukan\src\routes\index.js:21:24
app.js
const express = require('express');
const path = require('path');
const hbs = require('hbs');
const flash = require("connect-flash");
const passport = require("passport");
const db = require('./connection/db');
// Express Use
const app = express()
const port = 3000;
// Form Data Get
app.use(express.json());
app.use(express.urlencoded({extended:false}));
// HBS Handlebar use
app.set('view engine', 'hbs');
// Router Use
app.use('/', require(path.join(__dirname, 'routes/index.js')))
// Publics assess link (HBS)
const static_path = path.join(__dirname, '../publics');
app.use(express.static(static_path));
// View Set (HBS)
const views = path.join(__dirname, '../src/views');
const partials_path = path.join(__dirname, '../src/views/partials');
app.set('views', views);
hbs.registerPartials(partials_path);
//
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
index.js
const express = require('express');
const addUser = require('../models/register');
let passport = require("passport");
let LocalStrategy = require("passport-local").Strategy;
// const passport = require('../config/passport');
const {validationRegister, validationRegisterMsg} = require('../config/validator');
// const router = express.Router()
const router = require('express').Router()
router.get('/' , (req , res)=>{
res.render('index', {
title: "Welcome To Apna Dukan"
})
})
router.get('/welcome-to-apnadukan', (req , res)=>{
var errorMsg = req.flash('error')[0];
res.render('register', {
title: "Register | Welcome To Apna Dukan",
errorMsg,
page_name: "Register"
});
});
router.post('/welcome-to-apnadukan',
[
validationRegister(),
validationRegisterMsg,
passport.authenticate("local.register", {
successRedirect: "/login",
failureRedirect: "/welcome-to-apnadukan",
failureFlash: true,
}),
],
async (req , res)=>{
try {
if (req.session.oldUrl) {
let oldUrl = req.session.oldUrl;
req.session.oldUrl = null;
res.redirect(oldUrl);
} else {
res.redirect("/welcome-to-apnadukan");
}
} catch (error) {
req.flash("error", error.message);
res.status(400).send(error);
return res.redirect("/");
}
})
router.get('/login' , (req , res)=>{
res.render('login', {
title: "Login | Welcome To Apna Dukan",
page_name: "Login"
})
})
router.post('/login' , (req , res)=>{
req.send("Update");
})
router.get('/recover-password', (req, res)=>{
res.render('recoverpassword',{
title: "Recover Password | Welcome To Apna Dukan",
page_name: "Recover Password"
})
})
router.post('/recover-password', (req, res)=>{
res.render('recoverpassword',{
title: "Recover Password | Welcome To Apna Dukan",
page_name: "Recover Password"
})
})
router.get('/page' , (req , res)=>{
res.send('Hello World!')
})
module.exports = router
Validator.js
const { check, validationResult } = require("express-validator");
const validationRegister = (()=>{
return [
check('name', 'Name is required').not().isEmpty(),
check('username', 'Username is required').not().isEmpty().matches('/^(?![0-9]*$)[a-zA-Z0-9]+$/').withMessage('Only AlphaNumeric character is allowed').isLength({min:6,max:6}).withMessage('Minimum 6 characters required'),
check('email', 'Email is required').not().isEmpty().isEmail().withMessage('Email must be a valid email address.'),
check('password', 'Password is required').not().isEmpty().matches('/^(?=(.*[a-zA-Z].*){2,})(?=.*\d.*)(?=.*\W.*)[a-zA-Z0-9\S]{6,}$/').withMessage('Strong passwords with min 6 characters, at least two letters (not case sensitive), one number, one special character, space is not allowed'),
];
});
const validationRegisterMsg = (req, res, next)=>{
const errors = validationResult(req);
if (!errors.isEmpty()) {
let messages = [];
errors.array().forEach((error)=>{
messages.push(error.msg)
});
req.flash('error', messages);
// req.flash({error: messages})
return res.redirect('/register');
}
next();
};
module.exports = {validationRegister,validationRegisterMsg};
passport.js
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const User = require("../models/register");
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
passport.use(
"local.register",
new LocalStrategy(
{
nameField: 'name',
usernameField: 'username',
emailField: 'email',
passwordField: 'password',
passReqToCallBack: true
},
async (req, username, email, done) => {
try {
const username = await Customer_users.findOne({ username: username });
if (username) {
return done(null, false, { message: "Username already exists" });
}
const user = await Customer_users.findOne({ email: email });
if (user) {
return done(null, false, { message: "Email already exists" });
}
const newUser = await new User();
newUser.name = name;
newUser.username = username;
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
await newUser.save();
return done(null, newUser);
} catch (error) {
console.log(error);
return done(error);
}
}
)
);
You are configuring flash in your app after configuring the routes.
Moving this line app.use(flash()); before line app.use('/', require(path.join(__dirname, 'routes/index.js'))); will resolve the issue.
I'm trying to authenticate users locally using the passport-jwt strategy or with their google account using passport-google-oauth20 strategy. The local authentication with passport-jwt works fine but when I try to access the protected route after google signup, req.isAuthenticated() keeps returning false.
Here's what my code looks like
passport-jwt config
const passport = require("passport");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const User = require("../models/User");
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = process.env.JWT_SECRET;
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
User.findOne({ id: jwt_payload.id }, function (err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
})
);
passport-google-oauth20 config
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const User = require("../models/User");
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:5000/auth/google/protected",
},
(accessToken, refreshToken, profile, cb) => {
// console.log(profile);
const userInfo = {
googleId: profile.id,
fullname: profile.displayName,
email: profile.emails[0].value,
};
User.findOrCreate(userInfo, (err, user) => {
return cb(err, user);
});
}
)
);
controllers/auth.js
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const createError = require("../utils/error");
const jsonToken = require("../utils/verifyToken");
const passport = require("passport");
module.exports = {
googleAuth: passport.authenticate("google", {
session: false,
scope: ["email", "profile"],
}),
googleAuthRedirect: passport.authenticate("google", {
session: false,
failureRedirect: "auth/login",
}),
authRedirectCallBack: (req, res) => {
// const token = jsonToken.createToken({
// id: req.user._id,
// isAdmin: req.user.isAdnmin,
// services: req.user.services,
// });
// req.headers["Authorization"] = "Bearer " + token;
// console.log(req.headers["Authorization"]);
console.log(req.isAuthenticated()); //this line returns true
res.redirect("/api/protected");
},
};
routes/auth.js
const express = require("express");
const router = express.Router();
const controllers = require("../controllers/auth");
const {
googleAuth,
googleAuthRedirect,
authRedirectCallBack,
} = controllers;
router.route("/google").get(googleAuth);
router.route("/google/protected").get(googleAuthRedirect, authRedirectCallBack);
module.exports = router;
routes/protected.js
const router = require("express").Router();
const passport = require("passport");
router.get(
"/protected",
(req, res, next) => {
console.log("protected route returns: " + req.isAuthenticated()); //this line returns false
if (req.isAuthenticated()) {
res.send("this is the protected route");
} else {
return res.send("you're not authorized");
}
next();
},
passport.authenticate("jwt", { session: false }),
(req, res) => {
res.send("this is the protected route");
}
);
module.exports = router;
finally, server.js
const express = require("express");
const app = express();
const dotenv = require("dotenv");
dotenv.config();
const mongoose = require("mongoose");
const passport = require("passport");
require("./config/passportJwt");
require("./config/passportGoogle");
mongoose.connect("mongodb://localhost:27017/findersDB", {
useUnifiedTopology: true,
useNewUrlParser: true,
});
mongoose.connection.on("connected", () => console.log("DB connected!"));
app.use(express.json());
app.use(passport.initialize());
const authRoute = require("./routes/auth");
const protectedRoute = require("./routes/protected");
app.use("/auth", authRoute);
app.use("/api", protectedRoute);
app.use((err, req, res, next) => {
const errorMessage = err.message || "Something went wrong";
const errorStatus = err.status || 500;
return res.status(errorStatus).json({
success: false,
message: errorMessage,
status: errorStatus,
stack: err.stack,
});
});
app.listen(5000, () => console.log("Server is running on port 5000"));
I've tried every solution I've seen so far but none seems to work. Any help will be very much appreciated.
Earlier, I had a site with login forms and such but no database connectivity. I've now connected it to one with mongodb and have gotten some things working. I'm able to use RESTED to send requests and create accounts and validate accounts within the database.
I'm wondering, how would I be able to implement this functionality inside of a form? Where it would take the form details, query it through the database, and login if successful? Same with registering.
Here's the index:
const config = require('config');
var Joi = require('joi');
Joi.objectId = require('joi-objectid')(Joi);
const mongoose = require('mongoose');
const users = require('./routes/users');
const auth = require('./routes/auth');
var express = require("express");
var hbs = require('express-handlebars');
var app = express();
var bodyParser = require('body-parser');
if (!config.get('PrivateKey')) {
console.error('Error: PrivateKey is not defined.');
process.exit(1);
}
mongoose.connect('mongodb://localhost/airbnb')
.then(() => console.log('Now connected to MongoDB!'))
.catch(err => console.error('Something went wrong', err));
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'hbs');
app.engine('hbs', hbs({
extname: 'hbs',
defaultLayout: 'main',
layoutsDir: __dirname + '/views/layouts',
partialsDir: __dirname + '/views/partials/'
}));
app.use('/static', express.static('public'));
app.use(express.json());
app.use('/api/users', users);
app.use('/api/auth', auth);
var HTTP_PORT = process.env.PORT || 8080;
// call this function after the http server starts listening for requests
function onHttpStart() {
console.log("Express http server listening on: " + HTTP_PORT);
}
// setup a 'route' to listen on the default url path (http://localhost)
app.get("/", function (req, res) {
res.render('home', {layout: false})
});
// setup another route to listen on /about
app.get("/roomList", function (req, res) {
res.render('roomList', {layout: false})
});
app.get("/dashboard", function (req, res) {
res.render('dashboard', {layout: false})
});
// setup http server to listen on HTTP_PORT
app.listen(HTTP_PORT, onHttpStart);
here's user.js
// require mongoose and setup the Schema
var mongoose = require("mongoose");
var Joi = require('joi');
const joiObjectid = require("joi-objectid");
// connect to the localhost mongo running on default port 27017
mongoose.connect("mongodb://localhost/airbnb");
// define the company schema
// register the Company model using the companySchema
// use the web322_companies collection in the db to store documents
var User = mongoose.model('User', new mongoose.Schema({
email: {
type: String,
required: true,
minlength: 5,
maxlength: 255,
unique: true
},
password: {
type: String,
required: true,
minlength: 6,
maxlength: 55555
}
}));
// validate
function validateUser(user) {
const schema = Joi.object({
email: Joi.string().min(5).max(255).required().email(),
password: Joi.string().min(6).max(55555).required()
});
return schema.validate(user);
}
// export
exports.User = User;
exports.validate = validateUser;
here's users.js
const jwt = require('jsonwebtoken');
const config = require('config');
const bcrypt = require('bcrypt');
const _ = require('lodash');
const { User, validate } = require('../models/user');
const express = require('express');
const router = express.Router();
router.post('/', async (req,res) => {
const { error } = validate(req.body);
if (error) {
console.log(req.body.email);
console.log(req.body.password);
return res.status(400).send(error.details[0].message);
}
let user = await User.findOne({ email: req.body.email });
if (user) {
return res.status(400).send('That user already exists!');
} else {
user = new User(_.pick(req.body, ['name', 'email', 'password']));
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
await user.save();
const token = jwt.sign({_id: user._id }, config.get('PrivateKey'));
res.header('x-auth-token', token).send(_.pick(user, ['_id', 'name', 'email']));
}
});
module.exports = router;
here's auth.js
const config = require('config');
const jwt = require('jsonwebtoken');
const Joi = require('joi');
const bcrypt = require('bcrypt');
const _ = require('lodash');
const { User } = require('../models/user');
const express = require('express');
const router = express.Router();
router.post('/', async (req, res) => {
const { error } = validate(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
let user = await User.findOne({ email: req.body.email });
if (!user) {
return res.status(400).send('Incorrect email or password');
}
const validPassword = await bcrypt.compare(req.body.password, user.password);
if (!validPassword) {
return res.status(400).send('Incorrect email or password');
}
const token = jwt.sign({_id: user._id }, config.get('PrivateKey'));
res.send(token);
});
function validate(req)
{
const schema = Joi.object({
email: Joi.string().min(5).max(255).required().email(),
password: Joi.string().min(6).max(55555).required()
});
return schema.validate(req);
}
module.exports = router;
This is what my signup modal looks like currently:
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Registration</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form name="regForm" method="get" action="dashboard" onsubmit="return validateSignupForm()">
<div class="form-group mb-0">
<label for="formGroupEmail"></label>
<input type="email" class="form-control" id="formGroupEmail" placeholder="Email address"
name="signupEmail">
</div>
<div class="form-group mb-0">
<label for="formGroupPassword"></label>
<input type="password" class="form-control" id="formGroupPassword" placeholder="Password"
name="signupPassword">
</div>
</div>
<div class="modal-footer">
<input type="submit" value="Sign up" class="btn btn-danger">
</div>
</form>
</div>
</div>
</div>
function validateSignupForm() {
var signupEmail = document.forms["regForm"]["signupEmail"].value;
var signupPassword = document.forms["regForm"]["signupPassword"].value;
if (signupPassword.match(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$/)) {
return true;
}
else {
alert('Password must be between 6 and 20 characters and contain at least one number and uppercase letter');
return false;
}
}
Seems like that's a lot of efforts you are putting up with all that code, whereas you can simply use passport.js specifically passport-local-mongoose to get the register/login working with few lines of code. For submitting the form, You'll have to use something like ajax which can send requests to your backend server.
Im trying to display flash messages from passport.js but for some reason they are not showing - It is however showing "credentials not found" (but thats not the error message i want)
The code below - App,config and ejs (respectively)
const express = require('express')
const app = express()
const bcrypt = require('bcrypt')
app.set('view engine', 'ejs')
const initializePassport = require('./passport-config')
const passport = require('passport')
const flash = require('express-flash')
const session = require('express-session')
const accounts = [
]
app.use(passport.initialize())
initializePassport(passport, accounts.find(user => user.email === email))
app.use(express.urlencoded({ extended: true }))
app.use(passport.session())
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false
}))
app.use(flash())
app.get('/login', (req, res) => {
res.render('login')
})
app.post('/login', passport.authenticate(('local'), {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
app.get('/register', (req, res) => {
res.render('register')
})
app.post('/register', async (req, res) => {
const { name, email, password } = req.body
accounts.push({ id: Date.now().toString(), name, email, password: await bcrypt.hash(password, 10) })
console.log(accounts);
res.render('login')
})
app.listen(3000, () => {
console.log('server is running ');
})
//////////
const LocalStrategy = require('passport-local').Strategy
const bcrypt = require('bcrypt')
const initializePassport = (passport, getUserByEmail) => {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email)
if (user == null) {
return done(null, false, { message: "email is not on our db" })
}
try {
if (await bcrypt.compare(password), user.password) {
return done(null, user)
} else {
return done(null, false, { message: 'wrong password ' })
}
} catch (error) {
return done(error)
}
}
passport.use(new LocalStrategy(({ usenameField: 'email' }), authenticateUser))
}
module.exports = initializePassport
//////////
<h1>Login</h1>
<% if(messages.error){ %>
<p><%=messages.error%></p>
<% } %>
<form action="/login" method="POST">
<label for="email">email</label>
<input id="email" name="email" type="text">
<label for="password">password</label>
<input id="password" name="password" type="text">
<button>Log in</button>
</form>
<p> register</p>
Can anyone see the issue? I am following a tutorial and this seems to match exactly with his code
The documentation states that it requires cookieParser in order to work. I would add the following to your file:
const cookieParser = require('cookie-parser');
app.use(cookieParser());
Documentation: https://github.com/RGBboy/express-flash#usage
You could also potentially look at the source project for this extension called connect-flash. There is a wealth of information on implementing this package which should transfer well to the express-flash extension.
Working example: https://gist.github.com/vesse/9e23ff1810089bed4426