Image access permission issue using OpenLayers - ionic-framework

I am having a problem loading an image using the OpenLayers library. I am trying to load an image that is stored on the device dynamically. If I declare the options manually everything works as expected. If I try to load the image through path using file://... I get the following error:
Not allowed to load local resource: file:///storage/emulated/0/Android/data/io.ionic.starter/files/projects/1/layers/volume.png
To resolve this error I used the Ionic Web View path converter: window.Ionic.WebView.convertFileSrc() .
But this gives me another error, now related to CORS, considering that the access method now uses HTTP GET, which I quite don't understand since I trying to load a local image and not a remote one:
Access to image at 'http://localhost/_app_file_/storage/emulated/0/Android/data/io.ionic.starter/files/projects/1/layers/volume.png' from origin 'http://localhost:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET http://localhost/_app_file_/storage/emulated/0/Android/data/io.ionic.starter/files/projects/1/layers/volume.png net::ERR_FAILED
If I include the file in the assets folder and try to upload it, everything works as expected, but it's not how I want it to work.
Working code (manually configured):
let layerImage = new ImageLayer({
source: new Static({
url: 'assets/layers/volume.png',
crossOrigin: '',
projection: 'EPSG:31982',
imageExtent: layerExtent
}),
name: "layerImage",
visible: true,
});
this.map.addLayer(layerImage);
Not working code (dinamically configured inside a for loop):
let filePath = this.win.Ionic.WebView.convertFileSrc(this.file.externalDataDirectory + 'projects/' + this.projectId + '/layers/' + filename);
let layerImage = new ImageLayer({
source: new Static({
url: filePath,
crossOrigin: '',
projection: 'EPSG:31982',
imageExtent: layerExtent
}),
name: "layerImage",
visible: true,
});
this.map.addLayer(layerImage);
I saw in some related questions that this can be caused by debugging with Chrome, but the same problem happens if I not use it.

As per #Mike comment, the problem is solved if I remove the crossOrigin: '' option from Static.
let layerImage = new ImageLayer({
source: new Static({
url: filePath,
projection: 'EPSG:31982',
imageExtent: layerExtent
}),
name: "layerImage",
visible: true,
});

you can use url paramater as a function, maybe that helps.
const convertFileSrc = this.win.Ionic.WebView.convertFileSrc;
let layerImage = new ImageLayer({
source: new Static({
url: (extent) => {
return convertFileSrc(this.file.externalDataDirectory + 'projects/' + this.projectId + '/layers/' + filename);
},
crossOrigin: '',
projection: 'EPSG:31982',
imageExtent: layerExtent
}),
name: "layerImage",
visible: true,
});
this.map.addLayer(layerImage);

Related

StitchServiceError "aws: "aws_service" is a required string", errorCodeName: InvalidParameter

I'm setting up AWS S3 bucket to upload audio files to using MongoDB Stitch (here are the docs mongo s3 docs . After following the instructions and authenticating my user I keep geting this error when trying to upload the selected file: error image from console
On line 119 where the error is coming from I'm just catching the error after running AWS build:
const aws = stitchClient.getServiceClient(AwsServiceClient.factory, "AWS");
convertAudioToBSONBinaryObject(file).then((result) => {
const audiofile = mongodb.db("data").collection("audiofile");
//now we need an instance of AWS service client
const key = `${stitchClient.auth.user.id}-${file.name}`;
// const key = `${stitchClient.auth.user.id}-${file.name}`;
const bucket = "myBucketName";
const url =
"http://" + bucket + ".s3.amazonaws.com/" + encodeURIComponent(key);
const args = {
ACL: "public-read",
Bucket: bucket,
ContentType: file.type,
Key: key,
Body: result,
// aws_service: "s3",
};
// building the request
const request = new AwsRequest.Builder()
.withService("s3")
.withAction("PutObject")
.withRegion("us-east-1")
.withArgs(args);
aws
.execute(request.build)
.then((result) => {
console.log(result);
console.log(url);
return audiofile.insertOne({
owner_id: stitchClient.auth.user.id,
url,
file: {
name: file.name,
type: file.type,
},
Etag: result.Etag,
ts: new Date(),
});
})
.then((result) => {
console.log("last result", result);
})
.catch((err) => {
console.log(err);
});
});
My Stitch rule for s3 looks like this: Stitch rule for AWS s3
So it seems to me that everything is set up the way it's inteded to, but the error tells me I'm not passing all the needed args. I'd really appreciate any thoughts on how to fix this error.
P.S. If I change "AWS" to "AWS_S3" in this line :
const aws = stitchClient.getServiceClient(AwsServiceClient.factory, "AWS");
The error message changes to this:
StitchServiceError {message: "service not found: 'AWS_S3'", name: "StitchServiceError", errorCode: 18, errorCodeName: "ServiceNotFound",
And the log in Stitch shows this for information for both errors: Stitch Logs
The answer to this is a simple typo in this line:
aws
.execute(request.build)
.then((result)
build is a function so I just needed to call it - (request.build()).then((result).
Issue solved, thanks all!

request formData to API, gets “Network Error” in axios while uploading image

I am making a POST request to server to upload an image and sending formdata using axios in react-native. i am getting "Network Error". i also try fetch but nothing work.using react native image picker libeary for select image.in postman api working fine
formData.append('title', Title);
formData.append('class_id', selectClass._id)
formData.append('subject_id', checkSelected)
formData.append('teacher_id', userId)
formData.append('description', lecture);
formData.append('type', 'image');
var arr=[];
arr.push(imageSource)
arr.map((file,index)=>{
formData.append('file',{
uri:file.path,
type:file.type,
name:file.name
})
})
axios({
method: 'post',
url: URL + 'admin/assignment/create',
data: data,
headers: {
"content-type": "multipart/form-data",
'x-auth-token': token,
},
})
.then(function (response) {
//handle success
console.log('axios assigment post',response);
})
.catch(function (response) {
//handle error
console.log('axios assigment post',response);
});
Project keeps flipper java file under app > source > debug in react native > 0.62. There is an issue with Flipper Network that causes the problem in your case. If you remove the debug folder, you will not be able to debug Android with Flipper, so the best solution is upgrading Flipper version in android > gradle.properties to 0.46.0 that fixes the problem.
You can change it with this line
FLIPPER_VERSION=0.46.0
react-nativeandroid
The issue that I was facing which is close to what you are mentioning is that I was getting NetworkError when using image-picker and trying to upload the file using axios. It was working perfectly in iOS but not working in android.
This is how I solved the issue.
There are two independent issues at action here. Let’s say we get imageUri from image-picker, then we would use these following lines of code to upload from the frontend.
const formData = new FormData();
formData.append('image', {
uri : imageUri,
type: "image",
name: imageUri.split("/").pop()
});
The first issue is with the imageUri itself. If let’s say photo path is /user/.../path/to/file.jpg. Then file picker in android would give imageUri value as file:/user/.../path/to/file.jpg whereas file picker in iOS would give imageUri value as file:///user/.../path/to/file.jpg.
The solution for the first issue is to use file:// instead of file: in the formData in android.
The second issue is that we are not using proper mime-type. It is working fine on iOS but not on Android. What makes this worse is that the file-picker package gives the type of the file as “image” and it does not give proper mime-type.
The solution is to use proper mime-type in the formData in the field type. Ex: mime-type for .jpg file would be image/jpeg and for .png file would be image/png. We do not have to do this manually. Instead, you can use a very famous npm package called mime.
The final working solution is:
import mime from "mime";
const newImageUri = "file:///" + imageUri.split("file:/").join("");
const formData = new FormData();
formData.append('image', {
uri : newImageUri,
type: mime.getType(newImageUri),
name: newImageUri.split("/").pop()
});
I hope this helps to solve your problem :)
REACT NATIVE SOLUTION
If you are using Axios or Fetch in React Native and you got Network Error when uploading the file or data.
Try to commenting below line from the /android/app/src/main/java/com/{your_project}/MainApplication.java
its located around the 40-50 line
initializeFlipper(this, getReactNativeHost().getReactInstanceManager())
https://github.com/facebook/react-native/issues/28551
I faced the same issue. The following steps worked for me.
update FLIPPER_VERSION=0.52.0 latest
for formData code as below:
let formData = new FormData();
let file = {
uri: brand.uri,
type: 'multipart/form-data',
name: brand.uri
};
formdata.append('logo', file);
The type must be 'multipart/form-data' as the post header.
"react-native": "0.62.1",
"react": "16.11.0",
"axios": "^0.19.2",
weird solution i have to delete debug folder
in android ->app->source->debug
and restart the app again
its solve my problem. i think it's cache problem.
I had this problem and solve it via commenting the 43 line in
android/src/debug/.../.../ReactNativeFlipper.java
// builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
could you test it?
in my case, the solution was to change to
const headers = {
accept: 'application/json',
'content-type': 'multipart/form-data',
};
change this line: form_data.append('file', data);
To form_data.append('file', JSON.stringify(data));
from https://github.com/react-native-image-picker/react-native-image-picker/issues/798
You need to add this uesCleartextTraffic="true" to the AndroidManifest.xml file found inside the dir android/app/src/main/AndroidManifest.xml
<application ... android:usesCleartextTraffic="true"> Then, Because of issue with Flipper Network.
I commented initializeFlipper(this, getReactNativeHost().getReactInstanceManager())
in this file /android/app/src/main/java/com/{your_project}/MainApplication.java
Also, commenting out line number 43 in this file android/app/src/debug/java/com/**/ReactNativeFlipper.java
line43: builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
If using expo and expo-image-picker, then the problem is only with the image type and nothing else.
In the latest updates, they removed the bug related to path (as other answers mention to change the beginning of the path which was correct for the older versions).
Now to remove the problem, we need to change the type only and is mentioned by other answers to use mime which works fine;
import mime from 'mime'
const data = new FormData();
data.append('image', {
uri: image.uri,
name: image.uri.split('/').pop() // getting the text after the last slash which is the name of the image
type: mime.getType(image.uri) // image.type returns 'image' but mime.getType(image.uri) returns 'image/jpeg' or whatever is the type
})
In my case, after debbuging for a while, the issue was in nginx.
The image was "too big".
I Had to add annotations to the Kubernetes ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 20m
....
It was a bit tricky to debug since the request never got through the load balancer (nginx) to the Api service.
The "Network error" message didn't help a lot either.
I am using Expo SDK 42 (react-native v0.63). And I was using the expo-document-picker library to pick the documents & upload to server.
This is the code I am using to open the picker & get the metadata about the file.
const result = await DocumentPicker.getDocumentAsync({
type: 'image/*',
copyToCacheDirectory: false,
multiple: false,
});
if (result.type === 'success') {
const name_split = result.name.split('.');
const ext = name_split[name_split.length - 1];
// result.uri = 'file://' + result.uri;
result.type = helper.get_mime_type(ext);
delete result.size;
}
(You can write your function to get the mime type from the file extension or use some library from npm)
And this is the code I am using to upload the file to server:
const formdata = new FormData();
formdata.append('custom_param', 'value');
formdata.append('file', result); // 'result' is from previous code snippet
const headers = {
accept: 'application/json',
'content-type': 'multipart/form-data',
};
const opts = {
method: 'POST',
url: 'your backend endpoint',
headers: headers,
data: formdata,
};
return await axios.request(axiosopts);
The above code is the working code. I want to explain what I did wrong initially that was causing the Network Error in axios.
I had set copyToCacheDirectory to true initially and the uri I was getting in the result was in the format /data/path/to/file.jpeg. And I also tried appending file:// to beginning of the uri but it didn't work.
I then set copyToCacheDirectory to false and the uri I was getting in the result was in the format content://path/to/file.jpeg. And this didn't cause any Network Error in axios.
I have faced this error as well. I found out that I got this error because the file path is wrong and axios couldn't find the file. It is a weird error message when the uri is wrong though but that's what actually has happened. So double checking the uri of the file would fix the issue. Mainly consider file://.
I faced the same issue.
After capturing the photo wait for 10sec then start uploading. It worked for me.
Also got the same issue. I spent almost 4 days to find reason.
So in my case it was Content-Type: multipart/form-data. I forgot
indicate it. In Android it should be indicated explicitly...
After two days of searching for a solution, I found that the problem was in my rn-fetch-blob library, Changed it to in package.json dependencies
"rn-fetch-blob": "^0.12.0",
fix my Netowk issue and app crash on uploading. I am using
react-native-image-crop-picker
always send image and file in formdata in post api through axios in react js and react native
Blockquote
REACT NATIVE SOLUTION USING AXIOS
I face the same issue after upgrading react native cli project.
I'm using
"react-native": "0.70.6",
"react": "18.1.0",
"axios": "^1.1.3"
AND FLIPPER_VERSION=0.125.0
The below code solves my issue
const imageData = image;
const form = new FormData();
form.append("ProfileImage", {
type: imageData.mime,
uri: imageData.path,
name: imageData.path.split("/").pop(),
});
axios({
method: "put",
url: `${URL}/api/UploadPhoto`,
data: formData,
headers: {
"Content-Type": "multipart/form-data",
"cache-control": "no-cache",
},
processData: false,
contentType: false,
mimeType: "multipart/form-data",
});
For me, I didn't comment on any line from the /android/app/src/main/java/com/{your_project}/MainApplication.java
initializeFlipper(this, getReactNativeHost().getReactInstanceManager())
Also not changed FLIPPER_VERSION

Puppeteer's page.cookies() not retrieving all cookies shown in the Chrome dev tools

Using puppeteer, I am trying to retrieve all cookies for a specific web site (i.e. https://google.com) from Node.js.
My code is:
// Launch browser and open a new page
const browser = await puppeteer.launch({ headless: true, args: ['--disable-dev-shm-usage'] });
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle2' });
var cookies = await page.cookies();
console.log(cookies);
await browser.close();
It only retrieves 2 cookies, named 1P_JAR and NID. However, when I open the Chrome Dev tools, it shows a lot more.
I tried using the Chrome Dev Tools directly instead of puppeteer but I am getting the same results.
Is there another function I should call? Am I doing it correctly?
The page.cookies() call only gets cookies that are available to JavaScript applications inside the browser, and not the ones marked httpOnly, which you see in the Chrome DevTools. The solution is to ask for all available cookies through the Devtools protocol and then filter for the site you're interested in.
var data = await page._client.send('Network.getAllCookies');
You can utilise Chrome DevTools Protocol -> getAllCookies
To get all browser cookies, regardless of any flags.
const client = await page.target().createCDPSession();
const cookies = (await client.send('Network.getAllCookies')).cookies;
This will also play nice with typescript and tslint since something like
const cookies = await page._client.send('Network.getAllCookies');
Will raise an error TS2341: Property '_client' is private and only accessible within class 'Page'..
Thanks #try-catch-finally. I got it resolved and it was a simple rookie mistake.
I was comparing cookies in my own Google Chrome instance with the Puppeteer instance. However, in my instance, I was logged in to my Google account and Puppeteer (obviously) was not.
Google uses 2 cookies when you are NOT logged in and 12 when you are logged in.
If you use Playwright in place of Puppeteer, httponly cookies are readily accessible:
const { chromium } = require('playwright')
(async () => {
const browser = await chromium.launch()
const context = await browser.newContext()
const page = await context.newPage()
await page.goto('https://google.com', { waitUntil: 'networkidle' })
let allCookies = await context.cookies()
console.log (allCookies)
})();
returns:
[
{
sameSite: 'None',
name: '1P_JAR',
value: '2021-01-27-19',
domain: '.google.com',
path: '/',
expires: 1614369040.389115,
httpOnly: false,
secure: true
},
{
sameSite: 'None',
name: 'NID',
value: '208=VXtmbaUL...',
domain: '.google.com',
path: '/',
expires: 1627588239.572781,
httpOnly: true,
secure: false
}
]
Just use it await page.goto('https://google.com', { waitUntil: 'networkidle2' }). And you can get all the cookies related.

add local osrm sever to mapbox gl direction

I am going to use my local osrm server in order to do routing in a map based on mapbox GL. In mapbox-gl-directions.js there is a server part:
var initialState = {
api: 'https://api.mapbox.com/directions/v5/',
profile: 'driving-traffic',
unit: 'imperial',
proximity: false,
styles: [],
controls: {
inputs: true,
instructions: true
},
I would like to replace api with 'localhost:5000/route/v1/'
but it is not working.
Thanks.
OK. There are two lines that should be modified in mapbox-gl-directions.js.
First: change
api: 'https://api.mapbox.com/directions/v5/',
to
api: 'localhost:5000/route/v1/driving/',
Second: change
request.open('GET', api + 'mapbox/' + profile + '/' + query + '.json?' + options.join('&'), true);
to
request.open('GET', api + query + '?alternatives=true&steps=true&geometries=polyline&overview=full&annotations=true', true);

cordova background geolocation plugin on reboot

I am building an ionic app with background geolocation plugin https://github.com/mauron85/cordova-plugin-background-geolocation.
I want to make an app to send its location after reboot. The plugin I am using seems to have the option, but it is not working properly. An app only sends its location to the server only after execute an app at least once after every boot.
Any help or suggestion would be appreciated. Thank you in advance!
My code is below
Configuration
backgroundGeolocation.configure(callbackFn, failureFn, {
locationProvider: backgroundGeolocation.provider.ANDROID_ACTIVITY_PROVIDER,
desiredAccuracy: 10,
stationaryRadius: 10,
distanceFilter: 10,
interval: 60000,
maxLocations: 50,
startOnBoot: true, // from my understanding, this should make an app track its location even after reboot
stopOnTerminate: false
});
Callback Function
var callbackFn = function(location) {
console.log('[js] BackgroundGeolocation callback: ' + location.latitude + ',' + location.longitude);
// Do your HTTP request here to POST location to your server.
var link = API_URL;
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$http({
method: 'POST',
url: link,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
params: {
'device': 'android',
},
data: {
lat:location.latitude,
lng:location.longitude,
}
}).success(function(data){
console.log(data);
}).error(function(data){
console.log(data);
});
backgroundGeolocation.finish();
};
i hope you would have found your answer by now, posting this might help others too.
don't expect your callback to be executed after the reboot, as the activity might be killed, instead use url option of the plugin to continue sending your location updates to the server.