Good day developers, recently as been working in this node js app, and when implementing jwt library i got an error related to tghe verify() method in this jwt repo.
Kind of :
return secretCallback(null, secretOrPublicKey);
^
TokenExpiredError: jwt expired
The repo is structured in several folders:
controllers
middlewares
helpers
socket controllers
On my middleware folder, sepecifically in a file related to jwt validation i settled this:
file middleware jwt-validation
export {};
const { request, response } = require("express");
const User = require("../models/user-model");
const jwt = require("jsonwebtoken");
const jwtValidator = async (req = request, res = response, next) => {
const token_response = req.header("token-response");
if (!token_response) {
return res.status(401).json({
message: "Not valid token .You don't have authorization",
});
}
try {
const payload = await jwt.verify(token_response, process.env.SECRETKEYJWT)
const userAuth = await User.findById(payload.id);
if (userAuth.userState != true) {
return res.status(401).json({
message: "User inhabilitated",
});
}
if (!userAuth) {
return res.status(404).json({
message: "User not found",
});
}
req.user = userAuth;
next();
} catch (error) {
return res.status(500).json({
message: "Not valid token.Error 500",
});
}
};
module.exports = { jwtValidator };
file middleware jwt-validation-sockets
import { UserSchema } from "../interfaces";
const jwt = require("jsonwebtoken");
const User = require("../models/user-model");
const jwtValidatorRenew = async (
token: string = ""
): Promise<UserSchema | null> => {
if (token == "" || token.length < 10 || token == undefined) {
return null;
}
const payloadToken = await jwt.verify(token, process.env.SECRETKEYJWT)
const userTokenDecoded: UserSchema = User.findById(payloadToken.id);
if (userTokenDecoded?.userState) {
return userTokenDecoded;
} else {
return null;
}
};
module.exports = { jwtValidatorRenew };
file helper jwt-generator
const { request, response } = require("express");
const jwt = require("jsonwebtoken");
const createJWT = async (id = "", nickname = "") =>
return new Promise((resolve, reject) => {
const payloadInJWT = { id, nickname };
jwt.sign(
payloadInJWT,
process.env.SECRETKEYJWT,
{
expiresIn: 3600,
},
//calback
(error:any, token:string) => {
if (error) {
alert(error)
reject("Error creating token ");
} else {
resolve(token);
}
}
);
});
};
module.exports = { createJWT };
file socket-controller
const { jwtValidatorRenew } = require("../middlewares/jwt-validation-socket");
const { userData } = require("../helpers/helper-user-schema-data");
const { Socket } = require("socket.io");
const User = require("../models/user-model");
const {
ChatMessage,
Message,
MessagePrivate,
GroupChat,
} = require("../models/chat-model");
const chatMessage = new ChatMessage()
const socketController = async (socket = new Socket(), io) => {
const user = await jwtValidatorRenew(
socket.handshake.headers["token-response"]
);
try {
...some sockets flags
} catch (error) {
socket.disconnect();
}
};
module.exports = { socketController };
Ok, y'all I am in a pickle here. I've been working on all my firebase functions for a few days and thought I was making really good progress until I went to deploy after several days of testing with the firebase server and postman... It won't deploy T_T
The error I am getting in the terminal when I use firebase --debug deploy is:
2022-01-25T17:23:50.575Z] Total Function Deployment time: 57866
[2022-01-25T17:23:50.575Z] 1 Functions Deployed
[2022-01-25T17:23:50.575Z] 1 Functions Errored
[2022-01-25T17:23:50.575Z] 0 Function Deployments Aborted
[2022-01-25T17:23:50.575Z] Average Function Deployment time: 57864
Functions deploy had errors with the following functions:
api(us-central1)
[2022-01-25T17:23:50.713Z] Missing URI for HTTPS function in printTriggerUrls. This shouldn't happen
in functions: cleaning up build files...
[2022-01-25T17:23:50.719Z] >>> [apiv2][query] DELETE https://artifactregistry.googleapis.com/v1beta2/projects/lxai-mentor-matching/locations/us-central1/repositories/gcf-artifacts/packages/api [none]
[2022-01-25T17:23:50.722Z] >>> [apiv2][query] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/tags/list [none]
[2022-01-25T17:23:50.918Z] <<< [apiv2][status] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/tags/list 200
[2022-01-25T17:23:50.918Z] <<< [apiv2][body] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/tags/list {"child":["5fbdb989-6e6d-42bc-9a25-3073c3098d76"],"manifest":{},"name":"lxai-mentor-matching/gcf/us-central1","tags":[]}
[2022-01-25T17:23:50.918Z] >>> [apiv2][query] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/tags/list [none]
[2022-01-25T17:23:50.931Z] <<< [apiv2][status] DELETE https://artifactregistry.googleapis.com/v1beta2/projects/lxai-mentor-matching/locations/us-central1/repositories/gcf-artifacts/packages/api 404
[2022-01-25T17:23:50.933Z] <<< [apiv2][body] DELETE https://artifactregistry.googleapis.com/v1beta2/projects/lxai-mentor-matching/locations/us-central1/repositories/gcf-artifacts/packages/api {"error":{"code":404,"message":"Repository does not exist: \"projects/lxai-mentor-matching/locations/us-central1/repositories/gcf-artifacts\"","status":"NOT_FOUND"}}
[2022-01-25T17:23:51.061Z] <<< [apiv2][status] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/tags/list 200
[2022-01-25T17:23:51.063Z] <<< [apiv2][body] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/tags/list {"child":["cache"],"manifest":{"sha256:efea96d0dec08db58767f472cc16a3c17c277e41d844a61bbdb745e49c7cd8e6":{"imageSizeBytes":"421918451","layerId":"","mediaType":"application/vnd.docker.distribution.manifest.v2+json","tag":["api_version-15","latest"],"timeCreatedMs":"315532801000","timeUploadedMs":"1643131418106"}},"name":"lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76","tags":["api_version-15","latest"]}
[2022-01-25T17:23:51.064Z] >>> [apiv2][query] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/tags/list [none]
[2022-01-25T17:23:51.069Z] >>> [apiv2][query] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/api_version-15 [none]
[2022-01-25T17:23:51.230Z] <<< [apiv2][status] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/latest 202
[2022-01-25T17:23:51.231Z] <<< [apiv2][body] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/latest {"errors":[]}
[2022-01-25T17:23:51.250Z] <<< [apiv2][status] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/tags/list 200
[2022-01-25T17:23:51.250Z] <<< [apiv2][body] GET https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/tags/list {"child":[],"manifest":{"sha256:75f8940b6524c90f2b653b387e0cab4a9ae9f3dbebb2e5f4dfb03fc3345ead6f":{"imageSizeBytes":"13412478","layerId":"","mediaType":"application/vnd.docker.distribution.manifest.v2+json","tag":["latest"],"timeCreatedMs":"315532801000","timeUploadedMs":"1643131418618"}},"name":"lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache","tags":["latest"]}
[2022-01-25T17:23:51.251Z] >>> [apiv2][query] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/manifests/latest [none]
[2022-01-25T17:23:51.256Z] <<< [apiv2][status] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/api_version-15 202
[2022-01-25T17:23:51.256Z] <<< [apiv2][body] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/api_version-15 {"errors":[]}
[2022-01-25T17:23:51.257Z] >>> [apiv2][query] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/sha256:efea96d0dec08db58767f472cc16a3c17c277e41d844a61bbdb745e49c7cd8e6 [none]
[2022-01-25T17:23:51.386Z] <<< [apiv2][status] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/manifests/latest 202
[2022-01-25T17:23:51.386Z] <<< [apiv2][body] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/manifests/latest {"errors":[]}
[2022-01-25T17:23:51.387Z] >>> [apiv2][query] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/manifests/sha256:75f8940b6524c90f2b653b387e0cab4a9ae9f3dbebb2e5f4dfb03fc3345ead6f [none]
[2022-01-25T17:23:51.683Z] <<< [apiv2][status] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/sha256:efea96d0dec08db58767f472cc16a3c17c277e41d844a61bbdb745e49c7cd8e6 202
[2022-01-25T17:23:51.683Z] <<< [apiv2][body] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/manifests/sha256:efea96d0dec08db58767f472cc16a3c17c277e41d844a61bbdb745e49c7cd8e6 {"errors":[]}
[2022-01-25T17:23:51.728Z] <<< [apiv2][status] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/manifests/sha256:75f8940b6524c90f2b653b387e0cab4a9ae9f3dbebb2e5f4dfb03fc3345ead6f 202
[2022-01-25T17:23:51.729Z] <<< [apiv2][body] DELETE https://us.gcr.io/v2/lxai-mentor-matching/gcf/us-central1/5fbdb989-6e6d-42bc-9a25-3073c3098d76/cache/manifests/sha256:75f8940b6524c90f2b653b387e0cab4a9ae9f3dbebb2e5f4dfb03fc3345ead6f {"errors":[]}
[2022-01-25T17:23:51.852Z] Error: Failed to update function api in region us-central1
at /Users/tmac/.nvm/versions/node/v17.3.0/lib/node_modules/firebase-tools/lib/deploy/functions/release/fabricator.js:38:11
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Fabricator.updateV1Function (/Users/tmac/.nvm/versions/node/v17.3.0/lib/node_modules/firebase-tools/lib/deploy/functions/release/fabricator.js:255:32)
at async Fabricator.updateEndpoint (/Users/tmac/.nvm/versions/node/v17.3.0/lib/node_modules/firebase-tools/lib/deploy/functions/release/fabricator.js:136:13)
at async handle (/Users/tmac/.nvm/versions/node/v17.3.0/lib/node_modules/firebase-tools/lib/deploy/functions/release/fabricator.js:75:17)
Error: There was an error deploying functions
Having read a few other posts here I am super confused as to what the error is and where I can hunt it down. Everything has been working locally with firebase serve. When I check the log files I get this:
11:23:52.550 AM
api
{"#type":"type.googleapis.com/google.cloud.audit.AuditLog","status":
{"code":3,"message":"Function failed on loading user code. This is likely due to a bug in the user code. Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logs. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging. Please visit https://cloud.google.com/functions/docs/troubleshooting for in-depth troubleshooting documentation."},"authenticationInfo":{"principalEmail":"timmcmackenjr#gmail.com"},"serviceName":"cloudfunctions.googleapis.com","methodName":"google.cloud.functions.v1.CloudFunctionsService.UpdateFunction","resourceName":"projects/lxai-mentor-matching/locations/us-central1/functions/api"}
One post here was about space in a file name, but that's not my issue, another was about package.json so I'm posting mine here but not sure what I am looking for. Any idea on how to dig deeper or what to look for so I can get deploy working again?
package.json
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "16"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "^9.8.0",
"firebase-functions": "^3.14.1"
},
"devDependencies": {
"firebase-functions-test": "^0.2.0"
},
"private": true
}
index.js
const functions = require('firebase-functions');
const app = require('express')();
const { postOneScream } = require('./handlers/screams');
const {
signup,
login,
uploadImage,
addUserDetails,
} = require('./handlers/users');
const { addMentee, getMentees, updateMentee } = require('./handlers/mentees');
const { addMentor, getMentors, updateMentor } = require('./handlers/mentors');
const { FBAuth } = require('./util/fbAuth');
//**POST ROUTES**
// Scream routes - Testing post functionality for social media feed posts
app.post('/screams', FBAuth, postOneScream);
// Signup route
app.post('/signup', signup);
// Sign In route
app.post('/login', login);
// Upload an image route
app.post('/users/image', FBAuth, uploadImage);
// Add details to user profile
app.post('/users', FBAuth, addUserDetails);
// Mentee Signup / Update
app.post('/mentees', FBAuth, addMentee);
app.post('/mentees', FBAuth, updateMentee);
// Mentor Signup
app.post('/mentors', FBAuth, addMentor);
app.post('/mentors', FBAuth, updateMentor);
//**GET ROUTES**
// Get all mentees
app.get('/mentees', getMentees);
// Get all mentors
app.get('/mentors', getMentors);
//**Export API**
// export api allows us to use express for our function formating
exports.api = functions.https.onRequest(app);
users.js
const { admin, db } = require('../util/admin');
const firebase = require('firebase');
const config = require('../util/config');
firebase.initializeApp(config);
const {
validateSignupData,
validateLoginData,
reduceUserDetails,
} = require('../util/validators');
exports.signup = async (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle,
};
// Validating the fields for user signup
const { valid, errors } = validateSignupData(newUser);
if (!valid) return res.status(400).json(errors);
const noImg = 'no-img.png';
const userDoc = await db.doc(`/users/${newUser.handle}`).get();
if (userDoc.exists) {
return res.status(400).json({ handle: 'This handle already taken' });
} else {
// Create user
let userId;
await firebase
.auth()
.createUserWithEmailAndPassword(newUser.email, newUser.password)
.then((data) => {
userId = data.user.uid;
return data.user.getIdToken();
})
.then((userToken) => {
// Add User to Users Collection
const uToken = userToken;
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
createdAt: new Date().toISOString(),
imgURL: `https://firebasetorage.googleapis.com/v0/b/${config.storageBucket}/o/${noImg}?alt=media`,
userId,
};
db.doc(`/users/${newUser.handle}`).set(userCredentials);
return userToken;
})
.then((userToken) => {
return res
.status(201)
.json({ message: 'User created successfully', token: userToken });
})
.catch((err) => {
console.error(err);
if (err.code === 'auth/email-already-in-use') {
return res.status(400).json({ email: 'Email is already in use' });
} else {
return res.status(500).json({ error: err.code });
}
});
}
};
exports.login = (req, res) => {
const user = {
email: req.body.email,
password: req.body.password,
};
// Validating the fields for user login
const { valid, errors } = validateLoginData(user);
if (!valid) return res.status(400).json(errors);
// Log the user in and get a token
firebase
.auth()
.signInWithEmailAndPassword(user.email, user.password)
.then((data) => {
return data.user.getIdToken();
})
.then((token) => {
res.json({ token });
})
.catch((err) => {
console.error(err);
if (err.code === 'auth/wrong-password') {
return res.status(403).json({ general: 'Wrong credentials' });
} else {
return res.status(500).json({ error: err.code });
}
});
};
// Upload an image for user profile page
exports.uploadImage = (req, res) => {
const BusBoy = require('busboy');
const path = require('path');
const os = require('os');
const fs = require('fs');
const busboy = BusBoy({ headers: req.headers });
let imageFileName;
let imageToBeUploaded = {};
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
if (
mimetype !== 'image/jpeg' &&
mimetype !== 'image/png' &&
mimetype !== 'image/jpg'
) {
return res
.status(400)
.json({ error: 'Wrong file type, please use JPG/JPEG/PNG' });
}
const fileName = filename.filename + '';
const imageExtention = fileName.split('.')[fileName.split('.').length - 1];
// Not sure why we need to change file name but this is the tutorial recommendation
imageFileName = `${Math.round(
Math.random() * 10000000000,
)}.${imageExtention}`;
console.log(imageFileName);
const filePath = path.join(os.tmpdir(), imageFileName);
imageToBeUploaded = { filePath, mimetype };
file.pipe(fs.createWriteStream(filePath));
});
busboy.on('finish', () => {
admin
.storage()
.bucket()
.upload(imageToBeUploaded.filePath, {
resumable: false,
metadata: {
metadata: {
contentType: imageToBeUploaded.mimetype,
},
},
})
.then(() => {
const imgURL = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;
return db.doc(`/users/${req.user.handle}`).update({ imgURL });
})
.then(() => {
return res.json({ message: 'Image uploaded successfully' });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
});
busboy.end(req.rawBody);
};
// Add user details to user collection in db / user profile in react
exports.addUserDetails = (req, res) => {
let userDetails = reduceUserDetails(req.body);
db.doc(`/users/${req.user.handle}`)
.update(userDetails)
.then(() => {
return res.status(200).json({ message: 'Details added successfully' });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
screams.js
const { db } = require('../util/admin');
exports.postOneScream = (req, res) => {
const newScream = {
body: req.body.body,
userHandle: req.user.handle,
createdAt: new Date().toISOString(),
};
db.collection('screams')
.add(newScream)
.then((doc) => {
res.json({ message: `document ${doc.id} created successfully` });
})
.catch((err) => {
res.status(500).json({ error: 'something went wrong' });
console.error(err);
});
};
mentees.js
const { db } = require('../util/admin');
const { reduceMenteeDetails } = require('../util/validators');
// Add a mentee to the mentees collection
exports.addMentee = (req, res) => {
let menteeDetails = reduceMenteeDetails(req);
db.doc(`/mentees/${req.user.handle}`).set(menteeDetails)
.then(() => {
return res.status(200).json({ message: 'Details added successfully' });
}).catch(err => {
console.error(err);
return res.status(500).json({ error: err.code });
})
}
// Get all Mentees from the mentee collection
exports.getMentees = (req, res) => {
db.collection('mentees').get()
.then((data) => {
let mentees = [];
data.forEach((doc) => {
mentees.push(doc.data())
});
return res.json(mentees);
})
.catch(err => {
console.error(err);
return res.status(500).json({ error: err.code })
})
}
// Update an existing mentee
exports.updateMentee = (req, res) => {
let menteeDetails = reduceMenteeDetails(req);
db.doc(`/mentees/${req.user.handle}`).update(menteeDetails)
.then(() => {
return res.status(200).json({ message: 'Details added successfully' });
}).catch(err => {
console.error(err);
return res.status(500).json({ error: err.code });
})
}
mentors.js
const { db } = require('../util/admin');
const { reduceMentorDetails } = require('../util/validators');
// Add a mentor to the mentors collection
exports.addMentor = (req, res) => {
let mentorDetails = reduceMentorDetails(req);
db.doc(`/mentors/${req.user.handle}`)
.set(mentorDetails)
.then(() => {
return res.status(200).json({ message: 'Details added successfully' });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
// Get all mentors from the mentor collection
exports.getMentors = (req, res) => {
db.collection('mentors')
.get()
.then((data) => {
let mentors = [];
data.forEach((doc) => {
mentors.push(doc.data());
});
return res.json(mentors);
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
// Update an existing mentor
exports.updateMentor = (req, res) => {
let mentorDetails = reduceMentorDetails(req);
db.doc(`/mentors/${req.user.handle}`)
.update(mentorDetails)
.then(() => {
return res.status(200).json({ message: 'Details added successfully' });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
validators.js
// Helper functions for validation of signup form
// Check if a field is empty
const isEmpty = (string) => {
if (string.trim() === '') return true;
else return false;
};
// Check if an email is valid in format
const isEmail = (email) => {
const regEx =
/^(([^<>()[\]\.,;:\s#\"]+(\.[^<>()[\]\.,;:\s#\"]+)*)|(\".+\"))#(([^<>()[\]\.,;:\s#\"]+\.)+[^<>()[\]\.,;:\s#\"]{2,})$/i;
if (email.match(regEx)) return true;
else return false;
};
//Validate signup credential entered
exports.validateSignupData = (data) => {
let errors = {};
if (isEmpty(data.email)) {
errors.email = 'Must not be empty';
} else if (!isEmail(data.email)) {
errors.email = 'Must be a valid email';
}
if (isEmpty(data.password)) errors.password = 'Must not be empty';
if (data.password !== data.confirmPassword)
errors.confirmPassword = 'Passwords do not match';
if (isEmpty(data.handle)) errors.handle = 'Must not be empty';
return {
errors,
valid: Object.keys(errors).length === 0 ? true : false,
};
};
// Validate Login Credentials entered
exports.validateLoginData = (data) => {
let errors = {};
if (isEmpty(data.email)) errors.email = 'Must not be empty';
if (isEmpty(data.password)) errors.password = 'Must not be empty';
return {
errors,
valid: Object.keys(errors).length === 0 ? true : false,
};
};
// User Details Updater - Checks for non-answers/blanks and return dict
exports.reduceUserDetails = (data) => {
let userDetails = {};
if (!isEmpty(data.fullName.trim())) userDetails.fullName = data.fullName;
if (!isEmpty(data.jobTitle.trim())) userDetails.jobTitle = data.jobTitle;
if (!isEmpty(data.affiliation.trim()))
userDetails.affiliation = data.affiliation;
if (!isEmpty(data.homeLocation.trim()))
userDetails.homeLocation = data.homeLocation;
if (!isEmpty(data.isLatinX.trim())) userDetails.isLatinX = data.isLatinX;
if (!isEmpty(data.bio.trim())) userDetails.bio = data.bio;
if (!isEmpty(data.website.trim())) {
// If user doesn't include the http://
if (data.website.trim().substring(0, 4) !== 'http') {
userDetails.website = `http://${data.website.trim()}`;
} else userDetails.website = data.website;
}
if (!isEmpty(data.publicProfile.trim()))
userDetails.publicProfile = data.publicProfile;
return userDetails;
};
// Mentee Details Updater - Checks for non-answers/blanks and return dict
exports.reduceMenteeDetails = (data) => {
const answers = data.body;
let menteeDetails = {};
// Things we can pull from the data.user or just geneate
menteeDetails.createdAt = new Date().toISOString();
menteeDetails.userId = data.user.uid;
menteeDetails.email = data.user.email;
menteeDetails.handle = data.user.handle;
//Things we can pull from the user's info in the user collection
menteeDetails.fullName = answers.fullName;
menteeDetails.isLatinX = answers.isLatinX;
menteeDetails.currentLocation = answers.currentLocation;
// Questions we need to ask in the mentee sign up flow
if (!isEmpty(answers.gender.trim())) menteeDetails.gender = answers.gender;
if (!isEmpty(answers.countryOrigin.trim()))
menteeDetails.countryOrigin = answers.countryOrigin;
if (!isEmpty(answers.affiliation.trim()))
menteeDetails.affiliation = answers.affiliation;
if (!isEmpty(answers.position.trim()))
menteeDetails.position = answers.position;
if (!isEmpty(answers.scholarOrWebsite.trim())) {
// If user doesn't include the http://
if (answers.scholarOrWebsite.trim().substring(0, 4) !== 'http') {
menteeDetails.scholarOrWebsite = `http://${answers.scholarOrWebsite.trim()}`;
} else menteeDetails.scholarOrWebsite = answers.scholarOrWebsite;
}
if (answers.languages.length > 0) menteeDetails.languages = answers.languages;
if (!isEmpty(answers.timezone.trim()))
menteeDetails.timezone = answers.timezone;
if (answers.mentorshipArea.length > 0)
menteeDetails.mentorshipArea = answers.mentorshipArea;
if (!isEmpty(answers.motivationStatement.trim()))
menteeDetails.motivationStatement = answers.motivationStatement;
if (answers.prefferedOutcomes.length > 0)
menteeDetails.prefferedOutcomes = answers.prefferedOutcomes;
if (!isEmpty(answers.discussAfter.trim()))
menteeDetails.discussAfter = answers.discussAfter;
if (!isEmpty(answers.careerGoals.trim()))
menteeDetails.careerGoals = answers.careerGoals;
if (answers.skillMentorship.length > 0)
menteeDetails.skillMentorship = answers.skillMentorship;
if (answers.researchAreas.length > 0)
menteeDetails.researchAreas = answers.researchAreas;
if (answers.careerAdvice.length > 0)
menteeDetails.careerAdvice = answers.careerAdvice;
if (!isEmpty(answers.workshopReviewer))
menteeDetails.workshopReviewer = answers.workshopReviewer;
if (!isEmpty(answers.peerReviewedPubs.trim()))
menteeDetails.peerReviewedPubs = answers.peerReviewedPubs;
if (!isEmpty(answers.topTierReviewer.trim()))
menteeDetails.topTierReviewer = answers.topTierReviewer;
if (!isEmpty(answers.topTierPub.trim()))
menteeDetails.topTierPub = answers.topTierPub;
if (!isEmpty(answers.highImpactReviewer.trim()))
menteeDetails.highImpactReviewer = answers.highImpactReviewer;
if (answers.conferencePreference.length > 0)
menteeDetails.conferencePreference = answers.conferencePreference;
if (!isEmpty(answers.otherConferences.trim())) {
let conferences = answers.otherConferences.split(',');
menteeDetails.conferencePreference =
menteeDetails.conferencePreference.concat(conferences);
}
if (!isEmpty(answers.peerReviewedHighImpact))
menteeDetails.peerReviewedHighImpact = answers.peerReviewedHighImpact;
return menteeDetails;
};
// Mentee Details Updater - Checks for non-answers/blanks and return dict
exports.reduceMentorDetails = (data) => {
const answers = data.body;
let mentorDetails = {};
// Things we can pull from the data.user or just geneate
mentorDetails.createdAt = new Date().toISOString();
mentorDetails.userId = data.user.uid;
mentorDetails.email = data.user.email;
mentorDetails.handle = data.user.handle;
//Things we can pull from the user's info in the user collection
mentorDetails.fullName = answers.fullName;
mentorDetails.isLatinX = answers.isLatinX;
mentorDetails.currentLocation = answers.currentLocation;
// Questions we need to ask in the mentor sign up flow
if (!isEmpty(answers.gender.trim())) mentorDetails.gender = answers.gender;
if (!isEmpty(answers.countryOrigin.trim()))
mentorDetails.countryOrigin = answers.countryOrigin;
if (!isEmpty(answers.affiliation.trim()))
mentorDetails.affiliation = answers.affiliation;
if (!isEmpty(answers.position.trim()))
mentorDetails.position = answers.position;
if (!isEmpty(answers.scholarOrWebsite.trim())) {
// If user doesn't include the http://
if (answers.scholarOrWebsite.trim().substring(0, 4) !== 'http') {
mentorDetails.scholarOrWebsite = `http://${answers.scholarOrWebsite.trim()}`;
} else mentorDetails.scholarOrWebsite = answers.scholarOrWebsite;
}
if (answers.languages.length > 0) mentorDetails.languages = answers.languages;
if (!isEmpty(answers.timezone.trim()))
mentorDetails.timezone = answers.timezone;
if (!isEmpty(answers.previousMentor.trim()))
mentorDetails.previousMentor = answers.previousMentor;
if (answers.mentorshipArea.length > 0)
mentorDetails.mentorshipArea = answers.mentorshipArea;
if (!isEmpty(answers.hoursAvailable.trim()))
mentorDetails.hoursAvailable = answers.hoursAvailable;
if (answers.menteePref.length > 0)
mentorDetails.menteePref = answers.menteePref;
if (!isEmpty(answers.otherPref.trim())) {
let menteePrefs;
let newPref;
if (mentorDetails.menteePref.length !== 0)
menteePrefs = mentorDetails.menteePref;
else menteePrefs = [];
newPref = answers.otherPref.split(',');
menteePrefs = menteePrefs.concat(newPref);
mentorDetails.menteePref = menteePrefs;
}
if (answers.prefferedOutcomes.length > 0)
mentorDetails.prefferedOutcomes = answers.prefferedOutcomes;
if (!isEmpty(answers.otherOutcomes.trim())) {
let outcomes;
let newPref;
if (mentorDetails.prefferedOutcomes.length !== 0)
outcomes = mentorDetails.prefferedOutcomes;
else outcomes = [];
newPref = answers.otherPref.split(',');
outcomes = outcomes.concat(newPref);
mentorDetails.prefferedOutcomes = outcomes;
}
if (!isEmpty(answers.discussAfter.trim()))
mentorDetails.discussAfter = answers.discussAfter;
if (answers.skillMentorship.length > 0)
mentorDetails.skillMentorship = answers.skillMentorship;
if (answers.researchAreas.length > 0)
mentorDetails.researchAreas = answers.researchAreas;
if (answers.careerAdvice.length > 0)
mentorDetails.careerAdvice = answers.careerAdvice;
if (!isEmpty(answers.workshopReviewer))
mentorDetails.workshopReviewer = answers.workshopReviewer;
if (!isEmpty(answers.peerReviewedPubs.trim()))
mentorDetails.peerReviewedPubs = answers.peerReviewedPubs;
if (!isEmpty(answers.topTierReviewer.trim()))
mentorDetails.topTierReviewer = answers.topTierReviewer;
if (!isEmpty(answers.topTierPub.trim()))
mentorDetails.topTierPub = answers.topTierPub;
if (!isEmpty(answers.highImpactReviewer.trim()))
mentorDetails.highImpactReviewer = answers.highImpactReviewer;
if (answers.conferencePreference.length > 0)
mentorDetails.conferencePreference = answers.conferencePreference;
if (!isEmpty(answers.otherConferences.trim())) {
let otherconferences = answers.otherConferences.split(',');
let conferences = mentorDetails.conferencePreference;
conferences = conferences.concat(otherconferences);
mentorDetails.conferencePreference = conferences;
}
if (!isEmpty(answers.peerReviewedHighImpact))
mentorDetails.peerReviewedHighImpact = answers.peerReviewedHighImpact;
return mentorDetails;
};
I had added a package I needed in functions/index.js to my frontend with
/projectroot $ npm install -s [package]
, in stead of going into the /functions folder with the terminal and add it there to the /functions/package.json for node.js
/projectroot/functions $ npm install -s [package]
Why it causes so much trouble is because things work fine in emulator developer modus, but when you deploy it only sais it has an error, but doesn't tell you what the problem is.
More info on this: Firebase function failing to deploy
According to the error message, there isn't a whole lot of information about the problem you're presenting.
I know you used firebase –-debug deploy to retrieve the error message, and it returned an error on the user code, but what I would advise is that you look into the issue by viewing the log using firebase functions:log, which would be a lot easier.
There will be a visible representation of the exact issue. It could be something as simple as a missing package in some cases.
You can also use the following:
firebase functions:log --only <FUNCTION_NAME>
To have a better understanding of this command, you can access the Write and view logs.
Your firebase.json must include the following JSON code and it has to be similar to this in your case:
"hosting": {
"public": "public",
"rewrites" :[{
"source" : "**",
"function" : "api"
}],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
i have been facing this error of 401 unauthorized error when i tried to mount my isLoggedinMiddlware.js, and even when i can manage to print the token stored, it stil says its
authorised. Any advice or help would be appreciated! Have a nice day.
this is my isLoggedinMiddleware.js
const jwt = require("jsonwebtoken");
const JWT_SECRET = process.env.JWT_SECRET;
module.exports = (req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader === null || authHeader === undefined || !authHeader.startsWith("Bearer ")) {
res.status(401).send();
return;
}
const token = authHeader.replace("Bearer ", "");
jwt.verify(token, JWT_SECRET, { algorithms: ["HS256"] }, (error, decodedToken) => {
if (error) {
res.status(401).send();
return;
}
req.decodedToken = decodedToken;
next();
});
};
this is my post api
app.post("/listings/",isLoggedInMiddleware,(req,res)=>{
listings.insert(req.body,(error,result)=>{
if(error){
console.log(error)
console.log(req.body)
console.log(isLoggedInMiddleware)
res.status(500).send('Internal Server Error')
return;
}
console.log(result)
res.status(201).send({"Listing Id":result.insertId})
})
})
This is my front end
const baseUrl = "http://localhost:3000";
const loggedInUserID = parseInt(localStorage.getItem("loggedInUserID"));
const token = localStorage.getItem("token")
console.log(token)
if(token === null || isNaN(loggedInUserID)){
window.location.href = "/login/"
}else{
$('#logoff').click(function(){
event.preventDefault();
localStorage.removeItem('token')
localStorage.removeItem('loggedInUserID')
window.alert('Logging out now')
window.location.href = "/login/"
})
$(document).ready(function () {
$('#submitbtn').click((event) => {
const loggedInUserID = parseInt(localStorage.getItem("loggedInUserID"));
// middleware = {headers:{'Authorization':'Bearer '+token},data:{id: loggedInUserID}}
event.preventDefault();
const itemName = $("#itemName").val();
const itemDescription = $("#itemDescription").val();
const price = $('#price').val();
const image = $('#image').val();
const requestBody = {
itemName: itemName,
itemDescription: itemDescription,
price: price,
fk_poster_id: loggedInUserID,
imageUrl: image
}
console.log(requestBody);
axios.post(`${baseUrl}/listings/`,{headers:{'Authorization':'Bearer '+token},data:{id: loggedInUserID}}, requestBody)
.then((response) => {
window.alert("successfully Created")
})
.catch((error) => {
window.alert("Error")
console.log(requestBody)
})
})
})
}
i can managed to get the token i stored when i log in, however, it stills say 401 unauthorised.
Here is a Google Cloud Function calling Geofirestore after adding a document the Geofirestore way https://github.com/geofirestore/geofirestore-js
I have one item:
I've gotten {"sendit":{"domain":{"domain":null,"_events":{},"_eventsCount":1,"members":[]}}}
However,
I can't get it from query when the res.send({sendit}), is sent
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const GeoFirestore = require("geofirestore").GeoFirestore;
//const firestore = require('firebase/firestore');
const cors = require("cors")({
origin: true,
allowedHeaders: [
"Access-Control-Allow-Origin",
"Access-Control-Allow-Methods",
"Content-Type",
"Origin",
"X-Requested-With",
"Accept",
"Access-Control-Allow-Headers"
],
methods: ["POST", "OPTIONS"]
});
require('firebase/firestore');
//serviceAccount=yourServiceAccountKey.json
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "your_firebaseio_domain"
})
const firestoreRef = admin.firestore();
const geofirestore = new GeoFirestore(firestoreRef);
const geocollection = geofirestore.collection("planner");
exports.chooseCity = functions.https.onRequest((req, res) => {
// Google Cloud Function res.methods
res.set("Access-Control-Allow-Headers", "Content-Type");
res.set("Content-Type", "Application/JSON");
// CORS-enabled req.methods, res.methods
return cors(req, res, () => {
res.set("Access-Control-Allow-Headers", "Content-Type");
res.set("Content-Type", "Application/JSON");
var origin = req.get("Origin");
var allowedOrigins = [
"https://yourdomain.tld"
];
if (allowedOrigins.indexOf(origin) > -1) {
// Origin Allowed!!
res.set("Access-Control-Allow-Origin", origin);
if (req.method === "OPTIONS") {
// Method accepted for next request
res.set("Access-Control-Allow-Methods", "POST");
//SEND or end # option req.method
return res.status(200).send({});
} else {
// After request req.method === 'OPTIONS'
if (req.body) {
const radius = req.body.distance;
const center = new admin.firestore.GeoPoint(req.body.location[0], req.body.location[1])
const geoQuery = geocollection.near({ center, radius });
[**** Tried this ****]
let results = []
// Remove documents when they fall out of the query
geoQuery.on('key_exited', ($key) => {
const index = results.findIndex((place) => place.$key === $key);
if (index >= 0) results.splice(index, 1);
});
// As documents come in, add the $key/id to them and push them into our results
geoQuery.on('key_entered', ($key, result) => {
result.$key = $key;
results.push(result);
});
return res.status(200).send({results})
[**** Instead of this ****]
geoQuery.get()
.then(value => {
// All GeoDocument returned by GeoQuery,
//like the GeoDocument added above
const sendit = value.docs
res.status(200).send({sendit})
[**End**]
})
.catch(err => res.status(400).send(err))
} else {
res.status(200).send("no request body");
}
}
} else {
//Origin Bad!!
//SEND or end
return res.status(400).send("no access for this origin");
}
});
});
adding document, the geofirestore way, in a redux action
import { GeoFirestore } from "geofirestore";
export const createEvent = event => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
const firestore = getFirestore();
const geoFirestore = new GeoFirestore(firestore);
const geocollection = geoFirestore.collection("planner");
geocollection.add({
name: "Geofirestore",
score: 100,
// The coordinates field must be a GeoPoint!
coordinates: event.geopoint,
title: event.title,
body: event.body,
chosenPhoto: event.chosenPhoto,
date: event.date,
createdAt: event.createdAt,
updatedAt: event.updatedAt,
address: event.address,
location: event.location,
city: event.city,
etype: event.etype,
geopoint: event.geopoint
});
}}
also asked here: I'll update both https://github.com/geofirestore/geofirestore-js/issues/154
From the Geofirestore developer also has discussion & a working CORS for Cloud Functions
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const GeoFirestore = require('geofirestore').GeoFirestore;
admin.initializeApp();
const firestoreRef = admin.firestore();
const geofirestore = new GeoFirestore(firestoreRef);
const geocollection = geofirestore.collection('planner');
exports.chooseCity = functions.https.onRequest(async (request, response) => {
if (request.method === 'OPTIONS') {
response.set('Access-Control-Allow-Methods', 'POST');
return response.status(200).send({});
} else {
const radius = request.body.distance;
const center = new admin.firestore.GeoPoint(request.body.location[0],
request.body.location[1]);
// The data from a doc is returned as a function,
// so you just need to map and call the function
// sendit returns a single promise
const sendit = (await geocollection.near({ center, radius })
.get())
.docs
.map((doc) => ({ ...doc, data: doc.data() }));
return response.status(200).send({ sendit });
}
});
I'm fairly new to Firebase and Node.js. I have created this function in my Cloud Functions to login users with a custom token:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
var serviceAccount = require("./service-account.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: functions.config().firebase.databaseURL
});
const cors = require('cors')({origin: true});
exports.login = functions.https.onRequest((req, res) => {
cors(req, res, () => {
//doing some validation..
//get password from db and match it with input password
var userRef = admin.firestore().collection('users')
userRef.where('username', '==', username).get()
.then(snapshot => {
if(snapshot.size > 1){
res.status(200).send("Invalid account!");
return;
}
snapshot.forEach(doc => {
var userPass = doc.data().password;
//if password matches, generate token, save it in db and send it
if(userPass && password == userPass){
var uid = doc.data().uid;
var admin = Boolean(doc.data().admin);
var server = Boolean(doc.data().server);
var additionalClaims = {
admin: admin,
server: server
};
admin.auth().createCustomToken(uid, additionalClaims)
.then(function(customToken) {
res.status(200).send("token:" + customToken);
})
.catch(function(error) {
res.status(200).send("Token creation failed!");
});
//save token in db..
}else{
res.status(200).send("Invalid credentials!");
}
});
})
.catch(err => {
res.status(200).send("User authentication failed!");
});
});
});
I used the token generation method in the documentation, but whenever I try to login a user it throws the error:
TypeError: admin.auth is not a function
at snapshot.forEach.doc (/user_code/index.js:128:27)
at QuerySnapshot.forEach (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/reference.js:1012:16)
at userRef.where.get.then.snapshot (/user_code/index.js:110:13)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
What could it be that I'm doing wrong?
This declaration of admin:
var admin = Boolean(doc.data().admin);
is hiding this one:
const admin = require('firebase-admin');
Use a different name, such as:
var docAdmin = Boolean(doc.data().admin);