apache / cordova

Apache Cordova
https://cordova.apache.org/
584 stars 61 forks source link

ERR_CONNECTION_REFUSED despite access origin=* and correct content-secutiy-policy #345

Closed jwilkeson closed 1 year ago

jwilkeson commented 1 year ago

Bug Report

Problem

No matter what I do, I get net::ERR_CONNECTION_REFUSED when making a fetch() call to a domain running on http://localhost:8002

What is expected to happen?

fetch('http://localhost:8002') .then(response => { return response.text() }).then(response => alert(response)); should alert hello world

What does actually happen?

I get an error Failed to load resource: net::ERR_CONNECTION_REFUSED

Information

Command or Code

index.html

<!DOCTYPE html>
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
-->
<html>
    <head>
        <meta charset="utf-8">
        <!--
        Customize this policy to fit your own app's needs. For more guidance, please refer to the docs:
            https://cordova.apache.org/docs/en/latest/
        Some notes:
            * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
            * Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
                * Enable inline JS: add 'unsafe-inline' to default-src
        -->
        <meta http-equiv="Content-Security-Policy" content="default-src 'self' http://localhost:8002 data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">

        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover">
        <meta name="color-scheme" content="light dark">
        <link rel="stylesheet" href="css/index.css">
        <title>Hello World</title>
    </head>
    <body>
        <div class="app">
            <h1>Apache Cordova</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>
        <script src="cordova.js"></script>
        <script src="js/index.js"></script>
    </body>
</html>

index.js

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// Wait for the deviceready event before using any of Cordova's device APIs.
// See https://cordova.apache.org/docs/en/latest/cordova/events/events.html#deviceready
document.addEventListener('deviceready', onDeviceReady, false);

function onDeviceReady() {
    // Cordova is now initialized. Have fun!

    console.log('Running cordova-' + cordova.platformId + '@' + cordova.version);
    document.getElementById('deviceready').classList.add('ready');
    fetch('http://localhost:8002')
    .then(response => {
        return response.text()
    }).then(response => alert(response));
}

config.xml

<?xml version='1.0' encoding='utf-8'?>
<!-- <widget id="io.cordova.hellocordova" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:android="http://schemas.android.com/apk/res/android" > -->
<widget id="com.onegini.ExampleAppCordova" version="8.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    <name>HelloCordova</name>
    <description>Sample Apache Cordova App</description>
    <author email="dev@cordova.apache.org" href="https://cordova.apache.org">
        Apache Cordova Team
    </author>
    <content src="index.html" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <plugin name="cordova-plugin-whitelist" spec="1" />
    <access origin="*" />

    <!--  -->
    <platform name="android">
        <access origin="*" />
        <allow-intent href="http://*/*" />
        <allow-intent href="https://*/*" />
        <preference name="android-minSdkVersion" value="23" />
        <!-- Necessary to make sure that the deep app linking works properly -->
        <preference name="AndroidLaunchMode" value="singleTask" />
        <!-- <preference name="hostname" value="localhost" />
        <preference name="AndroidInsecureFileModeEnabled" value="true" /> -->
        <edit-config file="AndroidManifest.xml" target="/manifest" mode="merge">
            <manifest xmlns:tools="http://schemas.android.com/tools" />
        </edit-config>
        <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
            <application android:usesCleartextTraffic="true" />
        </edit-config>

        <plugin name="cordova-plugin-whitelist" spec="1" />
        <!-- <resource-file src="google-services.json" target="app/google-services.json" /> -->
    </platform>

    <!--  -->

</widget>

Environment, Platform, Device

package.json

{
  "name": "io.cordova.hellocordova",
  "displayName": "HelloCordova",
  "version": "1.0.0",
  "description": "A sample Apache Cordova application that responds to the deviceready event.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "ecosystem:cordova"
  ],
  "author": "Apache Cordova Team",
  "license": "Apache-2.0",
  "devDependencies": {
    "cordova-android": "^10.1.2",
    "cordova-browser": "^6.0.0",
    "cordova-plugin-whitelist": "1"
  },
  "cordova": {
    "platforms": [
      "browser",
      "android"
    ],
    "plugins": {
      "cordova-plugin-whitelist": {}
    }
  }
}

Version information

Checklist

Things I've Tried

jwilkeson commented 1 year ago

I ended up fixing this, part of the problem was that because the app was launched with https, I couldn't access localhost as it was only capable of http so I installed an ssl cert and also used https://10.0.0.2 which on android emulators directs to the hosts doc root and it seems to be working now.

breautek commented 1 year ago

Just for context, Android emulators are full virtual machines with their own virtual network stack. Therefore localhost will resolve to itself, the virtual machine, rather than the host machine. Physical devices will work the same way.

Additionally, if you're using schemes via <preference name="hostname" value="localhost" /> then the webview will (in simple terms) intercept http://localhost or (https://localhost if scheme is set to https) and remap urls to load from the local file system. It somewhat behaves like a virtual webserver that only the process itself can have access to.

That is why changing the url to use a private IP https://10.0.0.2 works. On mac/linux, you can look up your private ip using the ifconfig command, most home networks uses a 192.168.x.x ip scheme