Query parameters not received from deep linking - react native(expo) and node js - node.js

I am using openAuthSessionAsync to do a call to my backend and sending the url for deep linking
I am redirected back successfully to my app but i don't get query parameters that i send from backend with deep link
My react native app side:
const experiment = async()=>{
try{
let result = await WebBrowser.openAuthSessionAsync(`http://myaddress :3901/api/testig?linkingUri=${Linking.createURL(
"/?",
)}`,);
console.log(result)
}catch(errr){
console.log(errr)
}
}
My node js side:
router.get("/testig",(req,res)=>{
url = req.query.linkingUri
**//url is exp://myaddress:19000/--/?**
res.redirect(url+"?authToken=abc123")
})
I have also tried hard coding the url in backend but it only opens app back but with no parameters
And in my react native side in console i get this:
Object:{
"type":"dismiss",
}
UPDATE: Solved it by setting up eventListener for LINKING as follows
const handleDeepLink = (event)=>{
let data = Linking.parse(event.url)
setdata(data)
if(JSON.parse(data.queryParams.isSuccessful) == true)
{
props.navigation.navigate("thankyou")
}
}
React.useEffect(()=>{
Linking.addEventListener("url",handleDeepLink)
return(()=>{
Linking.removeEventListener("url")
})
},[])

use trycarch in the block to see errors and use var url
code lookslike
router.get("/testig",(req,res)=>{
try {
var url = req.query.linkingUri
return res.redirect(url+"?authToken=abc123")
} catch (e) {
console.log(e)
}
})

Related

How does one secure api keys on sveltekit 1.0

I am using ghost, i made an integration and i would like to hide the api key from the front-end. I do not believe i can set restrictions on the ghost cms (that would also work). And i do believe so +page.js files are run on the browser also, so im a little confused on how to achieve this?
The interal sveltekit module $env/static/private (docs) is how you use secure API keys. Sveltekit will not allow you to import this module into client code so it provides an extra layer of safety. Vite automatically loads your enviroment variables from .env files and process.env on build and injects your key into your server side bundle.
import { API_KEY } from '$env/static/private';
// Use your secret
Sveltekit has 4 modules for accessing enviroment variables
$env/static/private (covered)
$env/static/public accessiable by server and client and injected at build (docs)
$env/dynamic/private provided by your runtime adapter; only includes variables with that do not start with the your public prefix which defaults to PUBLIC_ and can only be imported by server files (docs)
$env/dynamic/public provided by your runtime adapter; only includes variables with that do start with the your public prefix which defaults to PUBLIC_ (docs)
You don't need to hide the key.
Ghost Content API Docs:
These keys are safe for use in browsers and other insecure environments, as they only ever provide access to public data.
One common way to hide your third-party API key(s) from public view is to set up proxy API routes.
The general idea is to have your client (browser) query a proxy API route that you provide/host, have that proxy route query the third-party API using your credentials (API key), and pass on the results from the third-party API back to the client.
Because the query to the third-party API takes place exclusively on the back-end, your credentials are never exposed to the client (browser) and thus not visible to the public.
In your use case, you would have to create 3 dynamic endpoint routes to replicate the structure of Ghost's API:
src/routes/api/[resource]/+server.js to match /posts/, /authors/, /tags/, etc.:
const API_KEY = <your_api_key>; // preferably pulled from ENV
const GHOST_URL = `https://<your_ghost_admin_domain>/ghost/api/content`;
export function GET({ params, url }) {
const { resource } = params;
const queryString = url.searchParams.toString();
return fetch(`${GHOST_URL}/${resource}/?key=${API_KEY}${queryString ? `&${queryString}` : ''}`, {
headers: {
'Accept-Version': '5.0' // Ghost API Version setting
}
});
}
src/routes/api/[resource]/[id]/+server.js to match /posts/{id}/, /authors/{id}/, etc.:
const API_KEY = <your_api_key>; // preferably pulled from ENV
const GHOST_URL = `https://<your_ghost_admin_domain>/ghost/api/content`;
export function GET({ params, url }) {
const { resource, id } = params;
const queryString = url.searchParams.toString();
return fetch(`${GHOST_URL}/${resource}/${id}/?key=${API_KEY}${queryString ? `&${queryString}` : ''}`, {
headers: {
'Accept-Version': '5.0' // Ghost API Version setting
}
});
}
src/routes/api/[resource]/slug/[slug]/+server.js to match /posts/slug/{slug}/, /authors/slug/{slug}/, etc.:
const API_KEY = <your_api_key>; // preferably pulled from ENV
const GHOST_URL = `https://<your_ghost_admin_domain>/ghost/api/content`;
export function GET({ params, url }) {
const { resource, slug } = params;
const queryString = url.searchParams.toString();
return fetch(`${GHOST_URL}/${resource}/slug/${slug}/?key=${API_KEY}${queryString ? `&${queryString}` : ''}`, {
headers: {
'Accept-Version': '5.0' // Ghost API Version setting
}
});
}
Then all you have to do is call your proxy routes in place of your original third-party API routes in your app:
// very barebones example
<script>
let uri;
let data;
async function get() {
const res = await fetch(`/api/${uri}`);
data = await res.json();
}
</script>
<input name="uri" bind:value={uri} />
<button on:click={get}>GET</button>
{data}
Note that using proxy API routes will also have the additional benefit of sidestepping potential CORS issues.

How to make Nodejs connect to Metamask account?

I have a backend write with Nodejs that can connect to contracts and perform functions in those contracts but the problem is I want my Metamask can pass only the account address to the backend. Is there any solution for this?
there are some third party packages like node-metamask
you can use them
add this code snippet in your views (hbs template engine) / HTML file.
When you load this page, the script will execute and it will get the metamask wallet address if it's installed.
<script>
async function connect()
{
if (window.ethereum) {
await window.ethereum.request({ method: "eth_requestAccounts" });
window.web3 = new Web3(window.ethereum);
const account = web3.eth.accounts;
const walletAddress = account.givenProvider.selectedAddress;
console.log(`Wallet: ${walletAddress}`);
window.location.href = `/setup?wallet=${walletAddress}`;
}
else {
alert("MetaMask is not installed");
}
}
</script>
after that, It will send the wallet address at a specific backend route to the express.
hence, you can perform actions in node JS with the integration of web3.
app.get('/setup', (req, res) => {
const address = req.query.wallet
app.locals.address = address
console.log(app.locals.address)
})
here's complete code example: https://github.com/billypentester/web3-dapp

How can I import an image from the express server to the client (in React)

I'm trying to show an image in react, which is neither a local image (in the client) nor an external image from the web but an image that is in the node.js express server (and I don't want to call it as if it was an external image, because the domain could change and it just doesn't seem right).
I know I can't just import it like I do with a local image in the client because we're speaking about different localhosts. I did try this:
loadImage = async (imageUrl) => {
const response = await fetch(`/api/images/${imageUrl}`);
const data = await response.json();
this.setState({ image: data });
}
componentDidMount() {
const { imageUrl } = this.props;
try {
this.loadImage(imageUrl);
} catch(error) {
console.log("Hay un error: " + error);
}
}
render() {
const { image } = this.state;
return(
<div>
<div>
<img alt="dontknowyet" className="blog-list-image" src={image} // and so on...
{image} does receive the correct path, but the image won't load and the console throws this error:
Not allowed to load local resource: file:///C:/Users/Dafna/Desktop/adrian/proyectos/esteticand/img/t4.jpg
So how can I make it work? and in case that I need to import the image file instead of just the link, how can I do that? (I can't update the state with an image...)
In order to access the path of the image it has to be done through the express server.
For example, if the (backend) server is running on port 4500 and the image is in a folder called images, and the express variable is called app, in the server file you have to use:
app.use(express.static('images'));
and then the image can be accessed in http://localhost:4500/nameoftheimage.jpg.
Do you have the api running on the same port as the React app?
You usually would make them run on different ports. Maybe it's got something to do with it.

Dynamic file names in react native require()

We're working on an app that will allow users to store templates with images on them, and pull those templates up later. This is for an AR environment using Viro on React Native.
We're trying to dynamically load an image into the component, and receiving errors when we require the filepath, which has been set to a variable:
const exampleUri = '/some/uri'
render() {
return(
<Viro3DObject
source={require(exampleUri)}
/>)
}
The URI for the source prop has to be dynamic, as the URIs are pulled from a Database.
We've tried storing the entire request in the database (in models/element.js):
const Sequelize = require('sequelize');
const db = require('../db');
const Element = db.define('element', {
sourceViro3DObject: {
type: Sequelize.STRING
}
});
sourceViro3DObject: `require('../../assets/emoji_heart/emoji_heart.vrx')`
When we called it in the React Native class component:
getObjectData = async () => {
try {
const {data} = await axios.get(`/api/elements/${this.props.elementId}`)
this.setState({sourceViro3DObject: data.sourceViro3DObject})
} catch (err) {
console.log(err)
}
}
async componentDidMount() {
await this.getObjectData()
}
But this simply sets state.sourceViro3DObject to a string:
'require('../../assets/emoji_heart/emoji_heart.vrx')'
We've tried setting the filepath directly to state as a string:
state.sourceViro3DObject = '../../assets/emoji_heart/emoji_heart.vrx'
and then call require on it:
require(this.state.sourceViro3DObject)
and received the following error:
Invalid prop `source` supplied to `Viro3DObject`
We've seen recommendations of storing the URIs in an object, but that can't work for us as we don't know what image is going to be used until it's pulled from the database. We can't hard-code them anywhere.
We'd appreciate any help with this!

Can I do the server rendering with data in React?

I'm working on react recently. I am using the server rendering with react-router, but it can only render the HTML from react components, and I need to get the initial data via ajax in componentDidMount().
The problem is for some pages/components, they need the initial data to render. So if users visit such a page directly(by typing url or refresh), the page broken, because the server cannot render it without initial data.
I'm thinking can I get the data from database and insert it to template when rendering in server? Just like what classic front-end template or PHP does.
If no way, what's the best practice for rendering first-page data?
Now my server code is like:
router.get('*', function(req, res) {
console.log('GET ADMIN');
match({
routes: appRoutes,
location: req.originalUrl
}, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500)
.send(error.message);
} else if (redirectLocation) {
res.status(302)
.redirect(redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
var content = renderToString(<RoutingContext {...renderProps}/>);
var html = swig.renderFile('src/client/admin.html', {
content: content
});
res.status(200)
.send(html);
} else {
res.status(404)
.send('Not found');
}
});
});
Finally I found the answer in GitHub: https://github.com/rackt/react-router/issues/1969#issuecomment-140988110
This method insert all data you need into the HTML template when rendering in server and get the data in front-end as context. All component can get the data via context.
I use a <DataWrapper> component to wrap the original root app component. On the server side when rendering:
data = JSON.stringify(data); // data is an object
ReactDOMServer.renderToString(<DataWrapper data={data}><RoutingContext {...renderProps}/></DataWrapper>)
and the <DataWrapper> is something like:
import React from 'react';
class DataWrapper extends React.Component {
getChildContext () {
return {
data: this.props.data
};
}
render () {
return this.props.children;
}
}
DataWrapper.childContextTypes = {
data: React.PropTypes.object.isRequired
};
export default DataWrapper;
on the client side:
var data = JSON.parse(document.getElementById('data').innerHTML),
history = createBrowserHistory();
ReactDOM.render(<DataWrapper data={ data }><Router history={ history }>{ routes }</Router></DataWrapper>, document.getElementById('app'));
get the data via context in components:
class someComponent extends React.Component {
constructor (props, context) {
super(props, context);
this.state = context.data.someData;
}
}
someComponent.contextTypes = {
data: React.PropTypes.object.isRequired
};
export default someComponent;
it works well
The problem with using an AJAX call for the initialisation is that it forces you to render first without the data and then to re-render once the data arrives.
A better way is to include the data in the page so it's there for your initial render. e.g.
<script>
var __INITIAL_DATA__ = { /* etc */ }
</script>
Yeah globals are ugly. But necessary in this instance. And you only use it once to initialise your React component. (Or your store if you're using Flux.)
And yes indeed, in isomorphic/universal apps you use the same data in your server side code. Just like in PHP and other server side languages. Only your server side code won't be pulling from a global variable. The data should be passed directly into the React component that you're mounting.

Resources