Routing within an Angular function - javascript

I have a login function here that allows a user to login and will navigate to a certain component (changepw) based on whether a piece of firebase information (active flag) is true or false. Even though I read read the data fine, when it is false, I am not getting a redirection with this code. change pw and /changepw have been tried. Help!
login(email: string, password: string): void {
this.firebaseAuth.signInWithEmailAndPassword(email, password)
.then(value => {
var userId = value.user.uid;
this.db.database.ref(('users/' + userId)).get().then(value => {
var userInfo = value.toJSON();
console.log(userInfo['active'])
if ( userInfo == false ) {
this.router.navigate(['changepw']);
} else {
this.router.navigate(['']);
}
})
})
.catch(err => {
console.log('Something went wrong:', err.message);
alert(err.message);
});
}

if you have something like this in app-routing.module.ts
const routes : Routes = [
{path:"changepw",component abcComponent}
]
then you should add front slash in navigate
this.router.navigate(['/changepw']);
share Routes in appRouting module also share if you have any error in console

I am not sure if you have tried this approach or not
this.router.navigate(['/', 'changepw']);
What this does is, after the / it will append the changepw route.
Since this.router.navigate([]); is an array, you need to split the path if it has a / or something lke that .

Related

How to extract page name and authToken from url using express get route in nodejs?

I have URL like this : http://localhost:3000/pageName and I am setting my express route like below:
app.get("/:pageName",(req,res)=>{
if (authentication === true) {
res.render(req.param.pageName}
})
Above works fine when it gets http://localhost:3000/demo.
However, when it gets this type of URL : http://localhost:3000/pageName/authToken like:
http://localhost:3000/demo/ubawfei346876jhat78gw8898ig8837yr
Route says cannot get demo/ubawfei346876jhat78gw8898ig8837yr and when I changed above code to this :
app.get("/:pageName/: authToken",(req,res) => {
if(authentication===true{
res.render(req.param.pageName}
)}
Then this type of url works fine :
http://localhost:3000/demo/ubawfei346876jhat78gw8898ig8837yr
But this type of URL : http://localhost:3000/demo is not working anymore
I would like to implement something like this when url is something like this
http://localhost:3000/demo then it should redirect to:
req.params.pageName
And when url looks like this http://localhost:3000/demo/yeieyhsi736hdh then it should varify token if varified redirect to:
req.params.pageName
You can implement both routes, and if an authToken is provided, then run a check on the authToken.
However, the way you are doing it right now would cause an endless redirect, as when any request to your /:pageName is made, it would be redirected to itself, so you need to provide a response with your content from within the route, not a redirect.
app.get("/:pageName", (req, res) => {
if (authentication) {
let pageName = req.params.pageName;
//Retrieve something with pageName and send it;
res.send(pageName);
} else {
res.send("Not authorised");
}
})
app.get("/:pageName/:authToken", (req, res) => {
let authToken = req.params.authToken;
if (isGood(authToken) && authentication) { //Fictious authToken check
let pageName = req.params.pageName;
//Retrieve something with pageName and send it;
res.send(pageName);
} else {
res.send("Not authorised");
}
})
Make your url like this http://localhost:3000/demo?token=As3ferrfmi5jr4jr4btdth54y6y6rty34t45t5y666666
app.get('/:pageName', (req, res) => {
//you can check if pageName is correct or not
if (req.query.token != undefined) {
const token = req.query.token;
// we must use strong secret, I am using "secret" for demo
jwt.verify(token,"secret", (err,data) => {
if (err) {
//do something if error occurs
} else {
// you can also do something with data which was stored on your token
res.render(req.params.pageName);
}
})
} else if (authenticate) {
// do something for authentication to access this else if
res.render(req.params.pageName);
} else {
// you can also render some error page or send 404 status
res.send('Something went wrong!');
}
});

How to persist firebase-auth over refresh with Nuxt?

I'm trying to set up Firebase authentication and currently, a user can sign up and I store their information within Vuex store.
If I refresh I lose everything and I do not know how to have it persist over the refresh. Could I use local storage, cookies, plugins? what would be the best way I have looked at a lot of answers and am still unclear.
I have tried using middleware but with no luck. I have also dabbled with using authStateChanged() but don't know where to implement it.
signup() {
// checking if username exists within our database
// creates a user through email and password
if(this.username && this.email && this.password) {
this.slug = slugify(this.username, {
replacement:'-',
remove: /[$*_+~.()'"\-:#]/g,
lower: true
})
// is creating a variable that stores slug then checks whether it exists, if it does we send feedback
let ref = db.collection('users').doc(this.slug)
ref.get().then( (doc) => {
if(doc.exists) {
this.feedback ="This Username already exists"
} else {
firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
.then((cred) => {
console.log("below is CREDANTIALS")
console.log(cred.user)
ref.set({
username: this.username,
user_id: cred.user.uid
})
this.$store.commit('setUser', cred.user.uid)
this.$store.commit('setUsername', this.username)
// localStorage.setItem('user_id', cred.user.uid)
})
.then(() => {
this.$router.push({name: 'explore'})
})
.catch(err => {
console.log(err)
// err is caught by catch and has a property called message
this.feedback = err.message
})
}
})
}
}
#TheWarderCoder Hey this is the snippet for saving to localstorage.
Just make a function inside methods.
saveUserData(id) {
localStorage.setItem('user-id', id)
}
and call it like this inside your signup methods.
this.saveUserData(id)
Good lucks !
Take a look at this plugin. https://github.com/robinvdvleuten/vuex-persistedstate
Nuxt.js integration is used like:
// nuxt.config.js
plugins: [{ src: '~/plugins/localStorage.js', ssr: false }]
// ~/plugins/localStorage.js
import createPersistedState from 'vuex-persistedstate'
export default ({store}) => {
window.onNuxtReady(() => {
createPersistedState({
key: 'yourkey',
paths: [...]
...
})(store)
})
}

JS: How to pass url through redirect function to login function

In my React/nextJS application I'm checking for a valid token in the getInitialProps static function.
I'm using this as a HOC - but this should not matter in this case.
If the the token is invalid (or missing) the user gets redirected to the login page. This is done by the redirect function as shown below. So far, so good.
How can I pass the url of the page from which the user gets redirected to the login component?
If the user is not logged in and is calling something like http://my-server.com/any-page, he gets redirected to the index page (http://my-server.com): There will be a login form. If the login is successful, I would like to redirect him back to the first called page: http://my-server.com/any-page
Call a restricted page as not logged in user
Redirect to index login page
After login redirect back to the page of 1.
I don't have a clue how to pass this information to the login function...
with-server-props.js
export default WrappedComponent =>
class extends Component {
static async getInitialProps (context) {
const { req, pathname } = context
let isValid = false
if (req && req.headers) {
const cookies = req.headers.cookie
if (typeof cookies === 'string') {
const cookiesJSON = jsHttpCookie.parse(cookies)
initProps.token = cookiesJSON['auth-token']
if (cookiesJSON['auth-token']) {
jwt.verify(cookiesJSON['auth-token'], secret, (error, decoded) => {
if (error) {
console.error(error)
} else {
isValid = true
}
})
}
}
}
// Redirect to index (=login) page if isValid is false
if (!isValid && pathname && pathname !== '/') {
redirect(context, pathname ? '/?ref=' + pathname : '/')
}
return initProps
}
render () {
return <WrappedComponent {...this.props} />
}
}
redirect.js
import Router from 'next/router'
export default (context, target) => {
if (context.res) {
// server
context.res.writeHead(303, { Location: target })
context.res.end()
} else {
// In the browser, we just pretend like this never even happened ;)
Router.replace(target)
}
}
pages/index.js
On index.js there is the submit function to login the user. There the user should be redirected to the initial page:
_onSubmit (event) {
this.props.loginMutation({
variables: { username, password }
}).then(response => {
const token = response.data.token
if (token) {
Cookies.set('auth-token', token, { expires: 1 })
this.props.client.resetStore().then(() => {
window.location.assign('/') // <-- Redirect to initial called page
})
}
})
}
In your with-server-props.js replace the path with an URL object
redirect(context, {
pathname: '/',
query: { redirect: req.url } // req.url should give you the current url on server side
})
this will add a redirect param to the url https://example.com/?redirect=/about
then you can get the url params on any page using the getInitialProps:
this.redirectUrl = (req && req.query['redirect']) ? decodeURIComponent(req.query['redirect']) : '/'
finally
window.location.assign(this.redirectUrl)
hope it helps, let me know.
What you need is react-router or more specifically the react-router-dom package. It's a breeze if you understand the way it works.
For your scenario, instead of calling redirect() when not authenticated, you use <Redirect to={url} />. This automatically does a browser url replace and updates global state.You'd have already subtly assigned a url that matches any special case to trap though. E.g. "/login/ref/:toref" will be the base expression to handle url "/login/ref/{specialaccess}".
Note the ":". It is the params matcher and is needed to retrieve the url in the login component.
As they say, a line of code is worth a thousand words. So I made a little project to demonstrate fully how one could implement some of the important features of react-router-dom.
Find here: https://codesandbox.io/s/y0znxpk30z
In the project when you try to access https://y0znxpk30z.codesandbox.io/specialaccess through the browser simulator, you get redirected to the special access page after becoming authenticated on login. Otherwise if you access https://y0znxpk30z.codesandbox.io then you get redirected to the home page after login.
Remember, you have to wrap any component that expects global props withRouter like this:
export default withRouter(component-name);
This provides this.props.location, this.props.history and this.props.match in every component because we already placed the app's root component inside the <BrowserRouter><BrowserRouter/> HOC available by default from the package.
With this.props.match we can easily refer to and redirect back to the url we specified in ":toref" previously.
You can read more about react-router here
jwt.verify function is used in an async callback manner.
That style is more fitting for the componentDidMount lifecycle method of the WrappedComponent used that way.
Passing a callback for it means that the value for isValid may never be updated early enough even when the client JWT token is a valid one and the user will always be redirected.
I suggest to use the synchronous variant without a callback (test to compare how much time before the wrapped component is rendered). Even better, convert jwt.verify callback style to a function that returns a promise so that it can be resolved in an await expression given that getInitialProps is an async function.
if (req && req.headers) {
const cookies = req.headers.cookie
if (typeof cookies === 'string') {
const cookiesJSON = jsHttpCookie.parse(cookies)
initProps.token = cookiesJSON['auth-token']
if (cookiesJSON['auth-token']) {
try {
const payload = jwt.verify(cookiesJSON['auth-token'], secret)
if (payload) {
isValid = true
}
} catch (err) {
isValid = false
}
}
}
}
Now in the _onsubmit method to redirect the user, you can get the ref query parameter value set in WrappedComponent.getInitialProps and use that to redirect the user.
const ref = new URLSearchParams(location.search).get('ref');
location.assign(`/${ref}`);
Pass the return url either as a query parameter or as location state to the login page. I found an example on the documentation page for Next.js on pushing a route with query parameters.
import Router from 'next/router'
const handler = () => {
Router.push({
pathname: '/about',
query: { name: 'Zeit' }
})
}
export default () => (
<div>
Click <span onClick={handler}>here</span> to read more
</div>
)
Instead of a Router.replace, try Router.push with the return url passed in from the HOC. Hope this helps.

ReCaptcha 2 working only once

I'm trying to implement a ReCaptcha but I can only get a valid g-recaptcha-response once when I'm testing it. If I'm trying to validate the captcha a second time, I check the box "I'm not a robot" then resolve the challenge but I'm getting the exact same g-recaptcha-response as the first time and I get a "timeout-or-duplicate" error from the webservice https://www.google.com/recaptcha/api/siteverify.
The only way I can get it to work again is to empty my local storage and my cookies.
Do you have any idea of why I have to do this ?
My code look like this :
HTML:
<div class="g-recaptcha"></div>
JS:
class CaptchaProtectedForm {
onSubmit() {
const captchaContainer = document.querySelector('.g-recaptcha');
this.captchaWidgetId = global.grecaptcha.render(capContainer, {
sitekey: '{site key}',
callback: this.doSubmit.bind(this),
});
}
doSubmit() {
const response = global.grecaptcha.getResponse(this.captchaWidgetId);
this.callBackend(parameters, response);
global.grecaptcha.reset();
}
}
Backend code (express router) :
router.route('/captchaProtectedEndpoint').post((req, res) => {
const {
headers: {
'x-captcha-token': captchaToken,
'x-forwarded-for': forwardedIp,
},
} = req;
const requestData = {
secret: conf.captchaSecretKey,
response: captchaToken,
remoteip: forwardedIp || req.connection.remoteAddress,
};
const requestConfig = {
uri: 'https://www.google.com/recaptcha/api/siteverify',
method: 'POST',
form: requestData,
};
request(requestConfig)
.then((captchaResponse) => {
if (captchaResponse.success) {
console.log('success', captchaResponse);
res.status(200).send();
} else {
console.log('failure', captchaResponse);
res.status(403).send();
}
})
.catch((err) => {
res.status(500).send();
});
});
Late edit:
The code works as expected, it was not working because of another module that was messing up with the local storage of our app.
This happens because, the g-recaptcha prevents duplicate entries. If you refresh the page and try to validate it, it will start the validation from the beginning. Also, if the data is stored in your cookies, the recaptcha will not start a fresh validation.

Facebook login in React Native

I am developing an app in React Native and I want to implement logging in with Facebook.
I have an API in Node.js where I handle the logic for users to log in, etc.
I use passport.js to let users log in with either Facebook or traditional Email.
I am opening an URL in my API with SafariView which is just a regular "WebView" directly in my app.
I have tried using the following code:
class FacebookButton extends Component {
componentDidMount() {
// Add event listener to handle OAuthLogin:// URLs
Linking.addEventListener('url', this.handleOpenURL);
// Launched from an external URL
Linking.getInitialURL().then((url) => {
if (url) {
this.handleOpenURL({ url });
}
});
}
componentWillUnmount() {
Linking.removeEventListener('url', this.handleOpenURL);
}
handleOpenURL({ url }) {
// Extract stringified user string out of the URL
const [, user_string] = url.match(/user=([^#]+)/);
this.setState({
// Decode the user string and parse it into JSON
user: JSON.parse(decodeURI(user_string))
});
if (Platform.OS === 'ios') {
SafariView.dismiss();
}
}
openURL(url) {
if (Platform.OS === 'ios') {
SafariView.show({
url: url,
fromBottom: true,
});
} else {
Linking.openURL(url);
}
}
render() {
return (
<Button
onPress={() => this.openURL('https://mywebsite.com/api/auth/facebook')}
title='Continue with Facebook'
...
so I guess I will have to do the authentication on URL https://mywebsite.com/api/auth/facebook and then send the user to an url that looks something like OAuthLogin://..., but I am not entirely sure how to use it.
Can anyone help me move in the right direction?
import { LoginManager, AccessToken } from 'react-native-fbsdk'; // add this file using npm i react-native-fbsdk
Create function
const onFacebookButtonPress = async () => {
// Attempt login with permissions
const result = await LoginManager.logInWithPermissions(['public_profile', 'email']);
if (result.isCancelled) {
throw 'User cancelled the login process';
}
// Once signed in, get the users AccesToken
const userInfo = await AccessToken.getCurrentAccessToken();
if (!userInfo) {
throw 'Something went wrong obtaining access token';
}
console.log('user info login', userInfo)
// Create a Firebase credential with the AccessToken
const facebookCredential = auth.FacebookAuthProvider.credential(userInfo.accessToken);
setGoogleToken(userInfo.accessToken)
// Sign-in the user with the credential
return auth().signInWithCredential(facebookCredential)
.then(() => {
//Once the user creation has happened successfully, we can add the currentUser into firestore
//with the appropriate details.
console.log('current User ####', auth().currentUser);
var name = auth().currentUser.displayName
var mSplit = name.split(' ');
console.log("mSplit ",mSplit);
let mUserDataFacebook = {
user_registration_email: auth().currentUser.email,
user_registration_first_name: mSplit[0],
user_registration_last_name: mSplit[1],
registration_type: 'facebook',
user_registration_role: "Transporter",
token: userInfo.accessToken,
user_image : auth().currentUser.photoURL,
};
console.log('mUserDataFacebook',mUserDataFacebook)
LoginWithGoogleFacebook(mUserDataFacebook) /// Call here your API
firestore().collection('users').doc(auth().currentUser.uid) //// here you can add facebook login details to your firebase authentication.
.set({
fname: mSplit[0],
lname: mSplit[1],
email: auth().currentUser.email,
createdAt: firestore.Timestamp.fromDate(new Date()),
userImg: auth().currentUser.photoURL,
})
//ensure we catch any errors at this stage to advise us if something does go wrong
.catch(error => {
console.log('Something went wrong with added user to firestore: ', error);
})
})
}
Call this function on button press onFacebookButtonPress()
For android need to setup and add facebook id in
android/app/src/main/res/values/strings.xml file
add these two lines.
YOUR_FACEBOOK_ID
fbYOUR_FACEBOOK_ID //Don't remove fb in this string value
/////////////add this code in AndroidMainfest.xml file
//////////This code add in MainApplication.java file
import com.facebook.FacebookSdk;
import com.facebook.appevents.AppEventsLogger;
/////////add code build.gradle file
implementation 'com.facebook.android:facebook-android-sdk:[5,6)'

Categories