├── HEAD ├── sample1 ├── .gitignore ├── manifest.json ├── README.md ├── .classpath ├── .project ├── build.xml ├── demo │ └── sample1.html └── src │ └── org │ └── webpki │ └── w2nb │ └── sample1 │ └── NativeClient.java ├── .gitattributes ├── proxy ├── install │ ├── apps │ │ ├── org.webpki.w2nb.sample1 │ │ │ ├── manifest.json │ │ │ └── org.webpki.w2nb.sample1.jar │ │ └── org.webpki.webpay.wallet3 │ │ │ ├── manifest.json │ │ │ └── org.webpki.webpay.wallet3.jar │ ├── logs │ │ └── .gitignore │ ├── libs │ │ ├── proxy-support.jar │ │ ├── bcprov-jdk15on-151.jar │ │ └── webpki.org-libext-1.0.0.jar │ ├── org.webpki.w2nb.moz.json │ ├── uninstall_proxy.bat │ ├── org.webpki.w2nb.json │ ├── install_proxy.bat │ ├── uninstall_proxy.sh │ └── install_proxy.sh ├── windows-build │ ├── w2nb-proxy.suo │ ├── w2nb-proxy.v12.suo │ ├── Debug │ │ └── w2nb-proxy.exe │ ├── w2nb-proxy │ │ ├── w2nb-proxy.vcxproj.user │ │ ├── w2nb-proxy.vcxproj.filters │ │ └── w2nb-proxy.vcxproj │ └── w2nb-proxy.sln ├── .gitignore ├── common.properties ├── .classpath ├── README.md ├── .project ├── java-build.xml ├── src.java │ └── org │ │ └── webpki │ │ └── w2nbproxy │ │ ├── LoggerConfiguration.java │ │ ├── StdoutJSONPipe.java │ │ ├── StdinJSONPipe.java │ │ ├── BrowserWindow.java │ │ └── ExtensionPositioning.java └── src.cpp │ └── w2nb-proxy.cpp ├── extension ├── debug │ ├── icon-128.png │ ├── manifest.json │ ├── content.js │ ├── inject.js │ └── extension.js ├── release │ ├── icon-128.png │ ├── manifest.json │ ├── content.js │ ├── inject.js │ └── extension.js ├── .project ├── README.md └── release-build.xml ├── firefox ├── extension │ ├── icon-128.png │ ├── manifest.json │ ├── content.js │ ├── inject.js │ └── extension.js ├── install │ ├── xpi │ │ └── web2native_bridge_emulator-1.0.xpi │ ├── uninstall_proxy.bat │ ├── install_proxy.bat │ ├── uninstall_proxy.sh │ └── install_proxy.sh └── .project ├── config ├── README.md └── AR2.xml /HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /sample1/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | .tmp/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable LF normalization for all files 2 | * -text -------------------------------------------------------------------------------- /sample1/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "callableFrom": ["*://*/*", "file:///*"] 3 | } -------------------------------------------------------------------------------- /proxy/install/apps/org.webpki.w2nb.sample1/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "callableFrom": ["*://*/*", "file:///*"] 3 | } -------------------------------------------------------------------------------- /proxy/install/logs/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /proxy/install/apps/org.webpki.webpay.wallet3/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "callableFrom": ["*://*/*", "file:///*"] 3 | } 4 | -------------------------------------------------------------------------------- /extension/debug/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/extension/debug/icon-128.png -------------------------------------------------------------------------------- /extension/release/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/extension/release/icon-128.png -------------------------------------------------------------------------------- /firefox/extension/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/firefox/extension/icon-128.png -------------------------------------------------------------------------------- /proxy/install/libs/proxy-support.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/install/libs/proxy-support.jar -------------------------------------------------------------------------------- /proxy/windows-build/w2nb-proxy.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/windows-build/w2nb-proxy.suo -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | [core] 2 | symlinks = false 3 | repositoryformatversion = 0 4 | filemode = false 5 | bare = true 6 | logallrefupdates = false 7 | -------------------------------------------------------------------------------- /proxy/windows-build/w2nb-proxy.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/windows-build/w2nb-proxy.v12.suo -------------------------------------------------------------------------------- /proxy/install/libs/bcprov-jdk15on-151.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/install/libs/bcprov-jdk15on-151.jar -------------------------------------------------------------------------------- /proxy/windows-build/Debug/w2nb-proxy.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/windows-build/Debug/w2nb-proxy.exe -------------------------------------------------------------------------------- /proxy/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | .tmp/ 3 | /install/*.exe 4 | /windows-build/w2nb-proxy/Debug 5 | /windows-build/w2nb-proxy.sdf 6 | /install/logs/*.* 7 | -------------------------------------------------------------------------------- /proxy/install/libs/webpki.org-libext-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/install/libs/webpki.org-libext-1.0.0.jar -------------------------------------------------------------------------------- /proxy/common.properties: -------------------------------------------------------------------------------- 1 | webpki-libext.jar=webpki.org-libext-1.0.0.jar 2 | 3 | common.app.dir=../proxy/install/apps 4 | common.lib.dir=../proxy/install/libs 5 | -------------------------------------------------------------------------------- /firefox/install/xpi/web2native_bridge_emulator-1.0.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/firefox/install/xpi/web2native_bridge_emulator-1.0.xpi -------------------------------------------------------------------------------- /proxy/windows-build/w2nb-proxy/w2nb-proxy.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /proxy/install/apps/org.webpki.w2nb.sample1/org.webpki.w2nb.sample1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/install/apps/org.webpki.w2nb.sample1/org.webpki.w2nb.sample1.jar -------------------------------------------------------------------------------- /proxy/install/apps/org.webpki.webpay.wallet3/org.webpki.webpay.wallet3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberphone/web2native-bridge/master/proxy/install/apps/org.webpki.webpay.wallet3/org.webpki.webpay.wallet3.jar -------------------------------------------------------------------------------- /proxy/install/org.webpki.w2nb.moz.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "org.webpki.w2nb.moz", 3 | "description": "Web2Native Bridge emulator", 4 | "path": "w2nb-proxy.exe", 5 | "type": "stdio", 6 | "allowed_extensions": ["w2nb@webpki.org"] 7 | } 8 | -------------------------------------------------------------------------------- /extension/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | extension 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /firefox/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | firefox 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /extension/README.md: -------------------------------------------------------------------------------- 1 | ###Chrome Extension Source 2 | This project holds the part of the Web2Native Bridge that must be installed 3 | in Chrome or Chromium to make it work. 4 | 5 | Note that there are no restrictions on domains or protocols, you can even 6 | launch this extension from a local HTML file. -------------------------------------------------------------------------------- /proxy/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample1/README.md: -------------------------------------------------------------------------------- 1 | ###Sample 1 2 | This project holds a miniscule application which high-lights 3 | the Web2Native Bridge API and technology. 4 | 5 | The application consists of two parts: 6 | * A Web page referring to a native application 7 | * The native application (in the emulator required to be in Java) 8 | 9 | Rebuilding the sample require **JDK 7** or **JDK 8** and **Ant**. 10 | -------------------------------------------------------------------------------- /proxy/README.md: -------------------------------------------------------------------------------- 1 | ###The Proxy 2 | This project holds all pieces of a "proxy" which must be installed in the native platform. 3 | 4 | The proxy is the component that makes it possible for the Web2Native Bridge breaking away from 5 | Native Messaging's single application model. 6 | 7 | The proxy would be a part of a "genuine" Web2Native Bridge implementation as well. It would 8 | typically be a part of the operating system. -------------------------------------------------------------------------------- /proxy/install/uninstall_proxy.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2014 The Chromium Authors. All rights reserved. 2 | :: Use of this source code is governed by a BSD-style license that can be 3 | :: found in the LICENSE file. 4 | 5 | :: Adapted for the Web2Native Bridge emulator by A.Rundgren 6 | 7 | :: Deletes the entries created by install_proxy.bat 8 | REG DELETE "HKCU\Software\Google\Chrome\NativeMessagingHosts\org.webpki.w2nb" /f 9 | -------------------------------------------------------------------------------- /firefox/install/uninstall_proxy.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2014 The Chromium Authors. All rights reserved. 2 | :: Use of this source code is governed by a BSD-style license that can be 3 | :: found in the LICENSE file. 4 | 5 | :: Adapted for the Web2Native Bridge emulator fo Firefox by A.Rundgren 6 | 7 | :: Deletes the entries created by install_proxy.bat 8 | REG DELETE "HKCU\Software\Mozilla\NativeMessagingHosts\org.webpki.w2nb.moz" /f 9 | -------------------------------------------------------------------------------- /sample1/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample1/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | sample1 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /proxy/install/org.webpki.w2nb.json: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | { 6 | "name": "org.webpki.w2nb", 7 | "description": "Web2Native Bridge emulator", 8 | "path": "w2nb-proxy.exe", 9 | "type": "stdio", 10 | "allowed_origins": ["chrome-extension://jphfmfbdedghfhhjijaogeloiehomfni/"] 11 | } 12 | -------------------------------------------------------------------------------- /proxy/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | proxy 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /proxy/install/install_proxy.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2014 The Chromium Authors. All rights reserved. 2 | :: Use of this source code is governed by a BSD-style license that can be 3 | :: found in the LICENSE file. 4 | 5 | :: Adapted for the Web2Native Bridge emulator by A.Rundgren 6 | 7 | :: Change HKCU to HKLM if you want to install globally. 8 | :: %~dp0 is the directory containing this bat script and ends with a backslash. 9 | REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\org.webpki.w2nb" /ve /t REG_SZ /d "%~dp0org.webpki.w2nb.json" /f 10 | COPY /Y "%~dp0..\windows-build\Debug\w2nb-proxy.exe" "%~dp0" 11 | -------------------------------------------------------------------------------- /extension/debug/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Web2Native Bridge emulator", 3 | "version": "1.0", 4 | "manifest_version": 2, 5 | "description": "Chrome Extension for emulating the Web2Native Bridge scheme", 6 | "icons": { 7 | "128": "icon-128.png" 8 | }, 9 | "content_scripts": [{ 10 | "matches": ["*://*/*", "file:///*"], 11 | "js": ["content.js"], 12 | "run_at": "document_end" 13 | }], 14 | "background": { 15 | "scripts": ["extension.js"] 16 | }, 17 | "web_accessible_resources": ["inject.js"], 18 | "permissions": ["nativeMessaging"], 19 | "short_name": "w2nb" 20 | } 21 | -------------------------------------------------------------------------------- /extension/release/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Web2Native Bridge emulator", 3 | "version": "1.0", 4 | "manifest_version": 2, 5 | "description": "Chrome Extension for emulating the Web2Native Bridge scheme", 6 | "icons": { 7 | "128": "icon-128.png" 8 | }, 9 | "content_scripts": [{ 10 | "matches": ["*://*/*", "file:///*"], 11 | "js": ["content.js"], 12 | "run_at": "document_end" 13 | }], 14 | "background": { 15 | "scripts": ["extension.js"] 16 | }, 17 | "web_accessible_resources": ["inject.js"], 18 | "permissions": ["nativeMessaging"], 19 | "short_name": "w2nb" 20 | } 21 | -------------------------------------------------------------------------------- /firefox/install/install_proxy.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2014 The Chromium Authors. All rights reserved. 2 | :: Use of this source code is governed by a BSD-style license that can be 3 | :: found in the LICENSE file. 4 | 5 | :: Adapted for the Web2Native Bridge emulator fo Firefox by A.Rundgren 6 | 7 | :: Change HKCU to HKLM if you want to install globally. 8 | :: %~dp0 is the directory containing this bat script and ends with a backslash. 9 | REG ADD "HKCU\Software\Mozilla\NativeMessagingHosts\org.webpki.w2nb.moz" /ve /t REG_SZ /d "%~dp0..\..\proxy\install\org.webpki.w2nb.moz.json" /f 10 | COPY /Y "%~dp0..\..\proxy\windows-build\Debug\w2nb-proxy.exe" "%~dp0..\..\proxy\install" 11 | -------------------------------------------------------------------------------- /extension/release-build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /firefox/extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Web2Native Bridge emulator", 3 | "version": "1.0", 4 | "manifest_version": 2, 5 | "description": "Firefox Extension for emulating the Web2Native Bridge scheme", 6 | "icons": { 7 | "128": "icon-128.png" 8 | }, 9 | "content_scripts": [{ 10 | "matches": ["*://*/*", "file:///*"], 11 | "js": ["content.js"], 12 | "run_at": "document_end" 13 | }], 14 | "background": { 15 | "scripts": ["extension.js"] 16 | }, 17 | "web_accessible_resources": ["inject.js"], 18 | "permissions": ["nativeMessaging"], 19 | "short_name": "w2nb", 20 | "applications": { 21 | "gecko": { 22 | "id": "w2nb@webpki.org", 23 | "strict_min_version": "50.0" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /firefox/install/uninstall_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2013 The Chromium Authors. All rights reserved. 3 | # Use of this source code is governed by a BSD-style license that can be 4 | # found in the LICENSE file. 5 | 6 | # Adapted for the Web2Native Bridge for Firefox by Anders Rundgren 7 | 8 | set -e 9 | 10 | DIR="$( cd "$( dirname "$0" )" && pwd )" 11 | if [ "$(uname -s)" = "Darwin" ]; then 12 | if [ "$(whoami)" = "root" ]; then 13 | TARGET_DIR="/Library/Mozilla/NativeMessagingHosts" 14 | else 15 | TARGET_DIR="$HOME/Library/Application Support/Mozilla/NativeMessagingHosts" 16 | fi 17 | else 18 | # Only local user support at the moment 19 | TARGET_DIR="$HOME/.mozilla/native-messaging-hosts" 20 | fi 21 | 22 | HOST_NAME=org.webpki.w2nb.moz 23 | MANIFEST=$HOST_NAME.json 24 | 25 | rm "$TARGET_DIR/$MANIFEST" 26 | echo "Native messaging host $TARGET_DIR/$MANIFEST has been uninstalled." 27 | 28 | -------------------------------------------------------------------------------- /proxy/windows-build/w2nb-proxy.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C++ Express 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "w2nb-proxy", "w2nb-proxy\w2nb-proxy.vcxproj", "{F1D8380D-1477-4341-BFD2-9706D40EDC3A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {F1D8380D-1477-4341-BFD2-9706D40EDC3A}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {F1D8380D-1477-4341-BFD2-9706D40EDC3A}.Debug|Win32.Build.0 = Debug|Win32 14 | {F1D8380D-1477-4341-BFD2-9706D40EDC3A}.Release|Win32.ActiveCfg = Release|Win32 15 | {F1D8380D-1477-4341-BFD2-9706D40EDC3A}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /proxy/windows-build/w2nb-proxy/w2nb-proxy.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /proxy/java-build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /proxy/install/uninstall_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2013 The Chromium Authors. All rights reserved. 3 | # Use of this source code is governed by a BSD-style license that can be 4 | # found in the LICENSE file. 5 | 6 | # Adapted for the Web2Native Bridge by Anders Rundgren 7 | 8 | set -e 9 | 10 | DIR="$( cd "$( dirname "$0" )" && pwd )" 11 | if [ "$(uname -s)" = "Darwin" ]; then 12 | if [ "$(whoami)" = "root" ]; then 13 | TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts" 14 | else 15 | TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" 16 | fi 17 | else 18 | if [ "$(whoami)" = "root" ]; then 19 | TARGET_DIR="/etc/opt/chrome/native-messaging-hosts" 20 | else 21 | if [ -d "$HOME/.config/google-chrome" ]; then 22 | CHROME_VARIANT=google-chrome 23 | if [ -d "$HOME/.config/chromium" ]; then 24 | echo "You have both Chrome and Chromium installed. Please patch the script!" 25 | exit 1 26 | fi 27 | else 28 | if [ -d "$HOME/.config/chromium" ]; then 29 | CHROME_VARIANT=chromium 30 | else 31 | echo "Can't find any Chrome variant!" 32 | exit 1 33 | fi 34 | fi 35 | TARGET_DIR="$HOME/.config/$CHROME_VARIANT/NativeMessagingHosts" 36 | fi 37 | fi 38 | 39 | HOST_NAME=org.webpki.w2nb 40 | MANIFEST=$HOST_NAME.json 41 | 42 | rm "$TARGET_DIR/$MANIFEST" 43 | echo "Native messaging host $TARGET_DIR/$MANIFEST has been uninstalled." 44 | 45 | -------------------------------------------------------------------------------- /proxy/src.java/org/webpki/w2nbproxy/LoggerConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2016 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.webpki.w2nbproxy; 19 | 20 | import java.io.File; 21 | 22 | import java.util.logging.FileHandler; 23 | import java.util.logging.Logger; 24 | import java.util.logging.SimpleFormatter; 25 | 26 | final public class LoggerConfiguration { 27 | 28 | private LoggerConfiguration() {} 29 | 30 | public static void init(Logger logger, String[] args) { 31 | try { 32 | logger.setUseParentHandlers(false); 33 | FileHandler fh = new FileHandler(args[0] + File.separator + "logs" + File.separator + args[1] + ".log"); 34 | logger.addHandler(fh); 35 | SimpleFormatter formatter = new SimpleFormatter(); 36 | fh.setFormatter(formatter); 37 | } catch (Exception e) { 38 | System.exit(3); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /firefox/install/install_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2013 The Chromium Authors. All rights reserved. 3 | # Use of this source code is governed by a BSD-style license that can be 4 | # found in the LICENSE file. 5 | 6 | # Adapted for the Web2Native Bridge for Firefox by Anders Rundgren 7 | 8 | set -e 9 | 10 | DIR="$( cd "$( dirname "$0" )" && pwd )" 11 | if [ "$(uname -s)" = "Darwin" ]; then 12 | CPP=clang 13 | CPP_OPTION=-lc++ 14 | if [ "$(whoami)" = "root" ]; then 15 | TARGET_DIR="/Library/Mozilla/NativeMessagingHosts" 16 | else 17 | TARGET_DIR="$HOME/Library/Application Support/Mozilla/NativeMessagingHosts" 18 | fi 19 | else 20 | # Only local user support at the moment 21 | CPP=g++ 22 | CPP_OPTION= 23 | TARGET_DIR="$HOME/.mozilla/native-messaging-hosts" 24 | fi 25 | 26 | HOST_NAME=org.webpki.w2nb.moz 27 | EXECUTABLE=w2nb-proxy 28 | HOST_PATH=$DIR/../../proxy/install/$EXECUTABLE 29 | MANIFEST=$HOST_NAME.json 30 | 31 | echo "Compiling proxy source to $HOST_PATH" 32 | $CPP $CPP_OPTION -w -o $HOST_PATH $DIR/../../proxy/src.cpp/$EXECUTABLE.cpp 33 | 34 | # Create directory to store native messaging host. 35 | mkdir -p "$TARGET_DIR" 36 | 37 | # Copy native messaging host manifest. 38 | cp "$DIR/../../proxy/install/$MANIFEST" "$TARGET_DIR" 39 | 40 | # Update host path in the manifest. 41 | sed -i -e "s%$EXECUTABLE.exe%$HOST_PATH%" "$TARGET_DIR/$MANIFEST" 42 | 43 | # Set permissions for the manifest so that all users can read it. 44 | chmod o+r "$TARGET_DIR/$MANIFEST" 45 | 46 | echo "Native messaging host $TARGET_DIR/$MANIFEST has been installed" 47 | -------------------------------------------------------------------------------- /proxy/src.java/org/webpki/w2nbproxy/StdoutJSONPipe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2016 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.webpki.w2nbproxy; 19 | 20 | import java.io.IOException; 21 | 22 | import org.webpki.json.JSONObjectWriter; 23 | import org.webpki.json.JSONOutputFormats; 24 | 25 | public class StdoutJSONPipe { 26 | 27 | public String writeJSONObject (JSONObjectWriter ow) throws IOException { 28 | byte[] utf8 = ow.serializeToBytes(JSONOutputFormats.NORMALIZED); 29 | int l = utf8.length; 30 | // Code only works for little-endian machines 31 | // Network order, heard of that Google? 32 | byte[] blob = new byte[l + 4]; 33 | blob[0] = (byte) l; 34 | blob[1] = (byte) (l >>> 8); 35 | blob[2] = (byte) (l >>> 16); 36 | blob[3] = (byte) (l >>> 24); 37 | for (int i = 0; i < l; i++) { 38 | blob[4 + i] = utf8[i]; 39 | } 40 | System.out.write(blob); 41 | return new String(utf8, "UTF-8"); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /sample1/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /proxy/src.java/org/webpki/w2nbproxy/StdinJSONPipe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2016 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.webpki.w2nbproxy; 19 | 20 | import java.io.DataInputStream; 21 | import java.io.IOException; 22 | 23 | import org.webpki.json.JSONObjectReader; 24 | import org.webpki.json.JSONParser; 25 | 26 | public class StdinJSONPipe { 27 | 28 | String jsonString; 29 | 30 | DataInputStream dis; 31 | 32 | public StdinJSONPipe() { 33 | dis = new DataInputStream(System.in); 34 | } 35 | 36 | public JSONObjectReader readJSONObject() throws IOException { 37 | byte[] byteBuffer = new byte[4]; 38 | dis.readFully(byteBuffer, 0, 4); 39 | // Code only works for little-endian machines 40 | // Network order, heard of that Google? 41 | int l = (byteBuffer[3]) << 24 | (byteBuffer[2] & 0xff) << 16 | 42 | (byteBuffer[1] & 0xff) << 8 | (byteBuffer[0] & 0xff); 43 | if (l > 100000) 44 | System.exit(3); 45 | byte[] utf8 = new byte[l]; 46 | dis.readFully(utf8); 47 | jsonString = new String(utf8, "UTF-8"); 48 | return JSONParser.parse(utf8); 49 | } 50 | 51 | public String getJSONString () { 52 | return jsonString; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /proxy/install/install_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2013 The Chromium Authors. All rights reserved. 3 | # Use of this source code is governed by a BSD-style license that can be 4 | # found in the LICENSE file. 5 | 6 | # Adapted for the Web2Native Bridge by Anders Rundgren 7 | 8 | set -e 9 | 10 | DIR="$( cd "$( dirname "$0" )" && pwd )" 11 | if [ "$(uname -s)" = "Darwin" ]; then 12 | CPP=clang 13 | CPP_OPTION=-lc++ 14 | if [ "$(whoami)" = "root" ]; then 15 | TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts" 16 | else 17 | TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" 18 | fi 19 | else 20 | CPP=g++ 21 | CPP_OPTION= 22 | if [ "$(whoami)" = "root" ]; then 23 | TARGET_DIR="/etc/opt/chrome/native-messaging-hosts" 24 | else 25 | if [ -d "$HOME/.config/google-chrome" ]; then 26 | CHROME_VARIANT=google-chrome 27 | if [ -d "$HOME/.config/chromium" ]; then 28 | echo "You have both Chrome and Chromium installed. Please patch the script!" 29 | exit 1 30 | fi 31 | else 32 | if [ -d "$HOME/.config/chromium" ]; then 33 | CHROME_VARIANT=chromium 34 | else 35 | echo "Can't find any Chrome variant!" 36 | exit 1 37 | fi 38 | fi 39 | TARGET_DIR="$HOME/.config/$CHROME_VARIANT/NativeMessagingHosts" 40 | fi 41 | fi 42 | 43 | HOST_NAME=org.webpki.w2nb 44 | EXECUTABLE=w2nb-proxy 45 | HOST_PATH=$DIR/$EXECUTABLE 46 | MANIFEST=$HOST_NAME.json 47 | 48 | echo "Compiling proxy source to $HOST_PATH" 49 | $CPP $CPP_OPTION -w -o $HOST_PATH $DIR/../src.cpp/$EXECUTABLE.cpp 50 | 51 | # Create directory to store native messaging host. 52 | mkdir -p "$TARGET_DIR" 53 | 54 | # Copy native messaging host manifest. 55 | cp "$DIR/$MANIFEST" "$TARGET_DIR" 56 | 57 | # Update host path in the manifest. 58 | sed -i -e "s%$EXECUTABLE.exe%$HOST_PATH%" "$TARGET_DIR/$MANIFEST" 59 | 60 | # Set permissions for the manifest so that all users can read it. 61 | chmod o+r "$TARGET_DIR/$MANIFEST" 62 | 63 | echo "Native messaging host $TARGET_DIR/$MANIFEST has been installed" 64 | -------------------------------------------------------------------------------- /extension/release/content.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | // DEBUG 21 | 22 | // Forward the message from inject.js to extension.js 23 | window.addEventListener("message", function(event) { 24 | // We only accept messages from ourselves 25 | if (event.source !== window || !event.data.src) 26 | return; 27 | 28 | // and forward to extension 29 | if (event.data.src === 'openreq') { 30 | // DEBUG 31 | chrome.runtime.sendMessage(event.data, function(response) { 32 | window.postMessage({res:response,src:'openres'}, '*'); 33 | // DEBUG 34 | }); 35 | } else if (event.data.src === 'webdis') { 36 | // DEBUG 37 | chrome.runtime.sendMessage(event.data); 38 | } else if (event.data.src === 'webmsg') { 39 | // DEBUG 40 | chrome.runtime.sendMessage(event.data); 41 | } else if (event.data.src === 'natmsg' || event.data.src === 'natdis') { 42 | // DEBUG 43 | } else { 44 | // DEBUG 45 | } 46 | }); 47 | 48 | // post messages from extension to injected page 49 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { 50 | // DEBUG 51 | window.postMessage({req:request,src:request.message ? 'natmsg' : 'natdis'}, '*'); 52 | }); 53 | 54 | // Inject inject.js to the DOM of every page. A horrible idea but it wasn't mine :-) 55 | var s = document.createElement('script'); 56 | s.src = chrome.extension.getURL('inject.js'); 57 | 58 | // remove script tag after script itself has loaded 59 | s.onload = function() {this.parentNode.removeChild(this);}; 60 | (document.head || document.documentElement).appendChild(s); -------------------------------------------------------------------------------- /firefox/extension/content.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | // DEBUG 21 | 22 | // Forward the message from inject.js to extension.js 23 | window.addEventListener("message", function(event) { 24 | // We only accept messages from ourselves 25 | if (event.source !== window || !event.data.src) 26 | return; 27 | 28 | // and forward to extension 29 | if (event.data.src === 'openreq') { 30 | // DEBUG 31 | browser.runtime.sendMessage(event.data, function(response) { 32 | window.postMessage({res:response,src:'openres'}, '*'); 33 | // DEBUG 34 | }); 35 | } else if (event.data.src === 'webdis') { 36 | // DEBUG 37 | browser.runtime.sendMessage(event.data); 38 | } else if (event.data.src === 'webmsg') { 39 | // DEBUG 40 | browser.runtime.sendMessage(event.data); 41 | } else if (event.data.src === 'natmsg' || event.data.src === 'natdis') { 42 | // DEBUG 43 | } else { 44 | // DEBUG 45 | } 46 | }); 47 | 48 | // post messages from extension to injected page 49 | browser.runtime.onMessage.addListener(function(request, sender, sendResponse) { 50 | // DEBUG 51 | window.postMessage({req:request,src:request.message ? 'natmsg' : 'natdis'}, '*'); 52 | }); 53 | 54 | // Inject inject.js to the DOM of every page. A horrible idea but it wasn't mine :-) 55 | var s = document.createElement('script'); 56 | s.src = browser.extension.getURL('inject.js'); 57 | 58 | // remove script tag after script itself has loaded 59 | s.onload = function() {this.parentNode.removeChild(this);}; 60 | (document.head || document.documentElement).appendChild(s); -------------------------------------------------------------------------------- /proxy/src.java/org/webpki/w2nbproxy/BrowserWindow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2016 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.webpki.w2nbproxy; 19 | 20 | import java.io.IOException; 21 | 22 | import org.webpki.json.JSONObjectReader; 23 | import org.webpki.json.JSONParser; 24 | 25 | import org.webpki.util.Base64URL; 26 | 27 | // This class represents the calling window argument provided by naigator.nativeConnect 28 | // It must match "inject.js" 29 | 30 | public class BrowserWindow { 31 | 32 | public double screenWidth; 33 | 34 | public double screenHeight; 35 | 36 | public double x; 37 | 38 | public double y; 39 | 40 | public double outerWidth; 41 | 42 | public double outerHeight; 43 | 44 | public double innerWidth; 45 | 46 | public double innerHeight; 47 | 48 | JSONObjectReader browserWindow; 49 | 50 | public BrowserWindow(String base64UrlEncodedParameters) throws IOException { 51 | browserWindow = JSONParser.parse(Base64URL.decode(base64UrlEncodedParameters)); 52 | if (browserWindow.hasProperty("screenWidth")) { 53 | screenWidth = browserWindow.getDouble("screenWidth"); 54 | screenHeight = browserWindow.getDouble("screenHeight"); 55 | x = browserWindow.getDouble("windowX"); 56 | y = browserWindow.getDouble("windowY"); 57 | outerWidth = browserWindow.getDouble("windowOuterWidth"); 58 | outerHeight = browserWindow.getDouble("windowOuterHeight"); 59 | innerWidth = browserWindow.getDouble("windowInnerWidth"); 60 | innerHeight = browserWindow.getDouble("windowInnerHeight"); 61 | } 62 | browserWindow.checkForUnread(); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return browserWindow.toString(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /extension/debug/content.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | console.debug('Content script loaded'); 21 | 22 | // Forward the message from inject.js to extension.js 23 | window.addEventListener("message", function(event) { 24 | // We only accept messages from ourselves 25 | if (event.source !== window || !event.data.src) 26 | return; 27 | 28 | // and forward to extension 29 | if (event.data.src === 'openreq') { 30 | console.debug('got open request'); 31 | chrome.runtime.sendMessage(event.data, function(response) { 32 | window.postMessage({res:response,src:'openres'}, '*'); 33 | console.debug('sent!'); 34 | }); 35 | } else if (event.data.src === 'webdis') { 36 | console.debug('disconnect-gotit!'); 37 | chrome.runtime.sendMessage(event.data); 38 | } else if (event.data.src === 'webmsg') { 39 | console.debug('webmsg-gotit!'); 40 | chrome.runtime.sendMessage(event.data); 41 | } else if (event.data.src === 'natmsg' || event.data.src === 'natdis') { 42 | console.debug('request-gotit:' + chrome.runtime.id); 43 | } else { 44 | console.debug('content-other' + event.data.src); 45 | } 46 | }); 47 | 48 | // post messages from extension to injected page 49 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { 50 | console.debug('Got incoming:' + JSON.stringify(request)); 51 | window.postMessage({req:request,src:request.message ? 'natmsg' : 'natdis'}, '*'); 52 | }); 53 | 54 | // Inject inject.js to the DOM of every page. A horrible idea but it wasn't mine :-) 55 | var s = document.createElement('script'); 56 | s.src = chrome.extension.getURL('inject.js'); 57 | 58 | // remove script tag after script itself has loaded 59 | s.onload = function() {this.parentNode.removeChild(this);}; 60 | (document.head || document.documentElement).appendChild(s); -------------------------------------------------------------------------------- /sample1/demo/sample1.html: -------------------------------------------------------------------------------- 1 | 2 | Sample #1 80 |

Web2Native Bridge "Emulator" - Sample #1

81 |
82 |
83 | 84 |
85 |

Messages:

86 |
87 |
The extension should
launch in this corner
88 | -------------------------------------------------------------------------------- /extension/release/inject.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | // DEBUG 21 | 22 | var _promise; 23 | 24 | var ports = []; 25 | 26 | var org = org || {}; 27 | org.webpki = org.webpki || {}; 28 | 29 | org.webpki.port = function(tabid) { 30 | this.tabid = tabid; 31 | ports[tabid] = this; 32 | }; 33 | 34 | org.webpki.port.prototype.addMessageListener = function(callback) { 35 | this.messageCallback = callback; 36 | }; 37 | 38 | org.webpki.port.prototype.addDisconnectListener = function(callback) { 39 | this.disconnectCallback = callback; 40 | }; 41 | 42 | org.webpki.port.prototype.disconnect = function() { 43 | var msg = {}; 44 | msg.src = 'webdis'; 45 | msg.tabid = this.tabid; 46 | window.postMessage(msg, '*'); 47 | }; 48 | 49 | org.webpki.port.prototype.postMessage = function(message) { 50 | var msg = {}; 51 | msg.src = 'webmsg'; 52 | msg.tabid = this.tabid; 53 | msg.message = message; 54 | window.postMessage(msg, '*'); 55 | }; 56 | 57 | // Forward the message from extension.js to inject.js 58 | window.addEventListener("message", function(event) { 59 | // We only accept messages from ourselves 60 | if (event.source !== window || !event.data.src) 61 | return; 62 | 63 | // and forward to extension 64 | if (event.data.src === "openres") { 65 | // DEBUG 66 | if (event.data.res.success) { 67 | _promise.resolve(new org.webpki.port(event.data.res.success)); 68 | } else if (event.data.res.err) { 69 | _promise.reject(event.data.res.err); 70 | } else { 71 | _promise.reject("Internal error"); 72 | } 73 | delete document._promise; 74 | } else if (event.data.src === "natmsg") { 75 | // DEBUG 76 | if (ports[event.data.req.tabid].messageCallback) { 77 | ports[event.data.req.tabid].messageCallback(event.data.req.message); 78 | } else { 79 | // DEBUG 80 | } 81 | } else if (event.data.src === "natdis") { 82 | // DEBUG 83 | if (ports[event.data.req.tabid].disconnectCallback) { 84 | ports[event.data.req.tabid].disconnectCallback(); 85 | } else { 86 | // DEBUG 87 | } 88 | } else if (event.data.src !== "webdis") { 89 | // DEBUG 90 | } 91 | }); 92 | 93 | navigator.nativeConnect = function(applicationName, optionalArguments) { 94 | return new Promise(function(resolve, reject) { 95 | var msg = {}; 96 | msg.src = 'openreq'; 97 | msg.origin = location.href; 98 | msg.application = applicationName; 99 | msg.window = {screenWidth: window.screen.width, 100 | screenHeight: window.screen.height, 101 | windowX: window.screenX, 102 | windowY: window.screenY, 103 | windowOuterWidth: window.outerWidth, 104 | windowOuterHeight: window.outerHeight, 105 | windowInnerWidth: window.innerWidth, 106 | windowInnerHeight: window.innerHeight}; 107 | msg.arguments = optionalArguments ? optionalArguments : {}; 108 | window.postMessage(msg, '*'); 109 | _promise = {resolve: resolve, reject: reject}; 110 | }); 111 | }; 112 | 113 | -------------------------------------------------------------------------------- /firefox/extension/inject.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | // DEBUG 21 | 22 | var _promise; 23 | 24 | var ports = []; 25 | 26 | var org = org || {}; 27 | org.webpki = org.webpki || {}; 28 | 29 | org.webpki.port = function(tabid) { 30 | this.tabid = tabid; 31 | ports[tabid] = this; 32 | }; 33 | 34 | org.webpki.port.prototype.addMessageListener = function(callback) { 35 | this.messageCallback = callback; 36 | }; 37 | 38 | org.webpki.port.prototype.addDisconnectListener = function(callback) { 39 | this.disconnectCallback = callback; 40 | }; 41 | 42 | org.webpki.port.prototype.disconnect = function() { 43 | var msg = {}; 44 | msg.src = 'webdis'; 45 | msg.tabid = this.tabid; 46 | window.postMessage(msg, '*'); 47 | }; 48 | 49 | org.webpki.port.prototype.postMessage = function(message) { 50 | var msg = {}; 51 | msg.src = 'webmsg'; 52 | msg.tabid = this.tabid; 53 | msg.message = message; 54 | window.postMessage(msg, '*'); 55 | }; 56 | 57 | // Forward the message from extension.js to inject.js 58 | window.addEventListener("message", function(event) { 59 | // We only accept messages from ourselves 60 | if (event.source !== window || !event.data.src) 61 | return; 62 | 63 | // and forward to extension 64 | if (event.data.src === "openres") { 65 | // DEBUG 66 | if (event.data.res.success) { 67 | _promise.resolve(new org.webpki.port(event.data.res.success)); 68 | } else if (event.data.res.err) { 69 | _promise.reject(event.data.res.err); 70 | } else { 71 | _promise.reject("Internal error"); 72 | } 73 | delete document._promise; 74 | } else if (event.data.src === "natmsg") { 75 | // DEBUG 76 | if (ports[event.data.req.tabid].messageCallback) { 77 | ports[event.data.req.tabid].messageCallback(event.data.req.message); 78 | } else { 79 | // DEBUG 80 | } 81 | } else if (event.data.src === "natdis") { 82 | // DEBUG 83 | if (ports[event.data.req.tabid].disconnectCallback) { 84 | ports[event.data.req.tabid].disconnectCallback(); 85 | } else { 86 | // DEBUG 87 | } 88 | } else if (event.data.src !== "webdis") { 89 | // DEBUG 90 | } 91 | }); 92 | 93 | navigator.nativeConnect = function(applicationName, optionalArguments) { 94 | return new Promise(function(resolve, reject) { 95 | var msg = {}; 96 | msg.src = 'openreq'; 97 | msg.origin = location.href; 98 | msg.application = applicationName; 99 | msg.window = {screenWidth: window.screen.width, 100 | screenHeight: window.screen.height, 101 | windowX: window.screenX, 102 | windowY: window.screenY, 103 | windowOuterWidth: window.outerWidth, 104 | windowOuterHeight: window.outerHeight, 105 | windowInnerWidth: window.innerWidth, 106 | windowInnerHeight: window.innerHeight}; 107 | msg.arguments = optionalArguments ? optionalArguments : {}; 108 | window.postMessage(msg, '*'); 109 | _promise = {resolve: resolve, reject: reject}; 110 | }); 111 | }; 112 | 113 | -------------------------------------------------------------------------------- /extension/debug/inject.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | console.debug('Injected page loaded'); 21 | 22 | var _promise; 23 | 24 | var ports = []; 25 | 26 | var org = org || {}; 27 | org.webpki = org.webpki || {}; 28 | 29 | org.webpki.port = function(tabid) { 30 | this.tabid = tabid; 31 | ports[tabid] = this; 32 | }; 33 | 34 | org.webpki.port.prototype.addMessageListener = function(callback) { 35 | this.messageCallback = callback; 36 | }; 37 | 38 | org.webpki.port.prototype.addDisconnectListener = function(callback) { 39 | this.disconnectCallback = callback; 40 | }; 41 | 42 | org.webpki.port.prototype.disconnect = function() { 43 | var msg = {}; 44 | msg.src = 'webdis'; 45 | msg.tabid = this.tabid; 46 | window.postMessage(msg, '*'); 47 | }; 48 | 49 | org.webpki.port.prototype.postMessage = function(message) { 50 | var msg = {}; 51 | msg.src = 'webmsg'; 52 | msg.tabid = this.tabid; 53 | msg.message = message; 54 | window.postMessage(msg, '*'); 55 | }; 56 | 57 | // Forward the message from extension.js to inject.js 58 | window.addEventListener("message", function(event) { 59 | // We only accept messages from ourselves 60 | if (event.source !== window || !event.data.src) 61 | return; 62 | 63 | // and forward to extension 64 | if (event.data.src === "openres") { 65 | console.debug('got open return'); 66 | if (event.data.res.success) { 67 | _promise.resolve(new org.webpki.port(event.data.res.success)); 68 | } else if (event.data.res.err) { 69 | _promise.reject(event.data.res.err); 70 | } else { 71 | _promise.reject("Internal error"); 72 | } 73 | delete document._promise; 74 | } else if (event.data.src === "natmsg") { 75 | console.debug('inject req:' + JSON.stringify(event.data.req)); 76 | if (ports[event.data.req.tabid].messageCallback) { 77 | ports[event.data.req.tabid].messageCallback(event.data.req.message); 78 | } else { 79 | console.debug('missing listener: ' + JSON.stringify(event.data.req)); 80 | } 81 | } else if (event.data.src === "natdis") { 82 | console.debug('inject disconnect:' + JSON.stringify(event.data.req)); 83 | if (ports[event.data.req.tabid].disconnectCallback) { 84 | ports[event.data.req.tabid].disconnectCallback(); 85 | } else { 86 | console.debug('missing listener: ' + JSON.stringify(event.data.req)); 87 | } 88 | } else if (event.data.src !== "webdis") { 89 | console.debug('page-other: ' + event.data.src); 90 | } 91 | }); 92 | 93 | navigator.nativeConnect = function(applicationName, optionalArguments) { 94 | return new Promise(function(resolve, reject) { 95 | var msg = {}; 96 | msg.src = 'openreq'; 97 | msg.origin = location.href; 98 | msg.application = applicationName; 99 | msg.window = {screenWidth: window.screen.width, 100 | screenHeight: window.screen.height, 101 | windowX: window.screenX, 102 | windowY: window.screenY, 103 | windowOuterWidth: window.outerWidth, 104 | windowOuterHeight: window.outerHeight, 105 | windowInnerWidth: window.innerWidth, 106 | windowInnerHeight: window.innerHeight}; 107 | msg.arguments = optionalArguments ? optionalArguments : {}; 108 | window.postMessage(msg, '*'); 109 | _promise = {resolve: resolve, reject: reject}; 110 | }); 111 | }; 112 | 113 | -------------------------------------------------------------------------------- /proxy/windows-build/w2nb-proxy/w2nb-proxy.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | {F1D8380D-1477-4341-BFD2-9706D40EDC3A} 18 | Win32Proj 19 | w2nbproxy 20 | 21 | 22 | 23 | Application 24 | true 25 | Unicode 26 | v140 27 | 28 | 29 | Application 30 | false 31 | true 32 | Unicode 33 | v140 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | false 47 | 48 | 49 | false 50 | 51 | 52 | 53 | NotUsing 54 | Level3 55 | Disabled 56 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 57 | MultiThreaded 58 | None 59 | false 60 | 61 | 62 | Console 63 | false 64 | $(OutDir)$(TargetName)$(TargetExt) 65 | NoErrorReport 66 | 67 | 68 | 69 | 70 | Level3 71 | NotUsing 72 | MaxSpeed 73 | true 74 | true 75 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 76 | 77 | 78 | Console 79 | true 80 | true 81 | true 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /extension/release/extension.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | console.log("Extension loaded"); 21 | 22 | var web2native_bridge = 'org.webpki.w2nb'; 23 | 24 | var ports = []; 25 | 26 | var BASE64URL = 27 | ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 28 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 29 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 30 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_']; 31 | 32 | function json2B64(jsonObject) { 33 | var string = JSON.stringify(jsonObject); 34 | var binArray = []; 35 | for (var n = 0; n < string.length; n++) { 36 | binArray.push(string.charCodeAt(n) & 0xFF); 37 | } 38 | var encoded = new String(); 39 | var i = 0; 40 | var modulo3 = binArray.length % 3; 41 | while (i < binArray.length - modulo3) { 42 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 43 | encoded += BASE64URL[((binArray[i++] << 4) & 0x30) | ((binArray[i] >>> 4) & 0x0F)]; 44 | encoded += BASE64URL[((binArray[i++] << 2) & 0x3C) | ((binArray[i] >>> 6) & 0x03)]; 45 | encoded += BASE64URL[binArray[i++] & 0x3F]; 46 | } 47 | if (modulo3 == 1) { 48 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 49 | encoded += BASE64URL[(binArray[i] << 4) & 0x30]; 50 | } 51 | else if (modulo3 == 2) { 52 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 53 | encoded += BASE64URL[((binArray[i++] << 4) & 0x30) | ((binArray[i] >>> 4) & 0x0F)]; 54 | encoded += BASE64URL[(binArray[i] << 2) & 0x3C]; 55 | } 56 | return encoded; 57 | } 58 | 59 | // Test that the native proxy is alive and kicking 60 | chrome.runtime.onStartup.addListener(function() { 61 | chrome.runtime.sendNativeMessage(web2native_bridge, {proxyVersion:"1.00"}, function(response) { 62 | if (response) { 63 | console.log("Extension successfully verified"); 64 | } else { 65 | alert('Web2Native Bridge library issue: ' + chrome.runtime.lastError.message); 66 | } 67 | }); 68 | }); 69 | 70 | function getPort(sender) { 71 | var port = ports[sender.tab.id]; 72 | if (!port) { 73 | alert('Missing port for: ' + sender.tab.id); 74 | } 75 | return port; 76 | } 77 | 78 | function getDisconnectPort(sender) { 79 | var port = getPort(sender); 80 | if (port) { 81 | delete ports[sender.tab.id]; 82 | } 83 | return port; 84 | } 85 | 86 | // When message is received from page send it to native 87 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { 88 | if(sender.id !== chrome.runtime.id || !sender.tab) { 89 | alert('Internal error'); 90 | return; 91 | } 92 | if (request.src === 'openreq') { 93 | var port = chrome.runtime.connectNative(web2native_bridge); 94 | ports[sender.tab.id] = port; 95 | port.onMessage.addListener(function(message) { 96 | // DEBUG 97 | chrome.tabs.sendMessage(sender.tab.id, {message:message,tabid:sender.tab.id}); 98 | }); 99 | port.onDisconnect.addListener(function() { 100 | // DEBUG 101 | getDisconnectPort(sender); 102 | chrome.tabs.sendMessage(sender.tab.id, {disconnect:true,tabid:sender.tab.id}); 103 | }); 104 | // DEBUG 105 | port.postMessage({url:request.origin, 106 | application:request.application, 107 | windowB64:json2B64(request.window), 108 | argumentsB64:json2B64(request.arguments)}); 109 | sendResponse({success:sender.tab.id}); 110 | } else if (request.src === 'webdis') { 111 | // DEBUG 112 | getDisconnectPort(sender).disconnect(); 113 | } else if (request.src === 'webmsg') { 114 | // DEBUG 115 | getPort(sender).postMessage(request.message); 116 | } else { 117 | sendResponse({err:{}}); 118 | } 119 | }); 120 | -------------------------------------------------------------------------------- /firefox/extension/extension.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | console.log("Extension loaded"); 21 | 22 | var web2native_bridge = 'org.webpki.w2nb.moz'; 23 | 24 | var ports = []; 25 | 26 | var BASE64URL = 27 | ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 28 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 29 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 30 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_']; 31 | 32 | function json2B64(jsonObject) { 33 | var string = JSON.stringify(jsonObject); 34 | var binArray = []; 35 | for (var n = 0; n < string.length; n++) { 36 | binArray.push(string.charCodeAt(n) & 0xFF); 37 | } 38 | var encoded = new String(); 39 | var i = 0; 40 | var modulo3 = binArray.length % 3; 41 | while (i < binArray.length - modulo3) { 42 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 43 | encoded += BASE64URL[((binArray[i++] << 4) & 0x30) | ((binArray[i] >>> 4) & 0x0F)]; 44 | encoded += BASE64URL[((binArray[i++] << 2) & 0x3C) | ((binArray[i] >>> 6) & 0x03)]; 45 | encoded += BASE64URL[binArray[i++] & 0x3F]; 46 | } 47 | if (modulo3 == 1) { 48 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 49 | encoded += BASE64URL[(binArray[i] << 4) & 0x30]; 50 | } 51 | else if (modulo3 == 2) { 52 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 53 | encoded += BASE64URL[((binArray[i++] << 4) & 0x30) | ((binArray[i] >>> 4) & 0x0F)]; 54 | encoded += BASE64URL[(binArray[i] << 2) & 0x3C]; 55 | } 56 | return encoded; 57 | } 58 | 59 | // Test that the native proxy is alive and kicking 60 | browser.runtime.sendNativeMessage(web2native_bridge, {proxyVersion:"1.00"}, function(response) { 61 | if (response) { 62 | console.log("Extension successfully verified"); 63 | } else { 64 | console.log('Web2Native Bridge library issue: ' + browser.runtime.lastError.message); 65 | } 66 | }); 67 | 68 | function getPort(sender) { 69 | var port = ports[sender.tab.id]; 70 | if (!port) { 71 | console.log('Missing port for: ' + sender.tab.id); 72 | } 73 | return port; 74 | } 75 | 76 | function getDisconnectPort(sender) { 77 | var port = getPort(sender); 78 | if (port) { 79 | delete ports[sender.tab.id]; 80 | } 81 | return port; 82 | } 83 | 84 | // When message is received from page send it to native 85 | browser.runtime.onMessage.addListener(function(request, sender, sendResponse) { 86 | 87 | /* 88 | console.log('sender='+ JSON.stringify(sender) + '\n' + JSON.stringify(browser.runtime)); 89 | 90 | if(sender.id !== browser.runtime.id) { 91 | console.log('Internal error'); 92 | return; 93 | } 94 | */ 95 | if (request.src === 'openreq') { 96 | var port = browser.runtime.connectNative(web2native_bridge); 97 | ports[sender.tab.id] = port; 98 | port.onMessage.addListener(function(message) { 99 | // DEBUG 100 | browser.tabs.sendMessage(sender.tab.id, {message:message,tabid:sender.tab.id}); 101 | }); 102 | port.onDisconnect.addListener(function() { 103 | // DEBUG 104 | // getDisconnectPort(sender); 105 | browser.tabs.sendMessage(sender.tab.id, {disconnect:true,tabid:sender.tab.id}); 106 | }); 107 | // DEBUG 108 | port.postMessage({url:request.origin, 109 | application:request.application, 110 | windowB64:json2B64(request.window), 111 | argumentsB64:json2B64(request.arguments)}); 112 | sendResponse({success:sender.tab.id}); 113 | } else if (request.src === 'webdis') { 114 | // DEBUG 115 | getDisconnectPort(sender).disconnect(); 116 | } else if (request.src === 'webmsg') { 117 | // DEBUG 118 | getPort(sender).postMessage(request.message); 119 | } else { 120 | sendResponse({err:{}}); 121 | } 122 | }); 123 | -------------------------------------------------------------------------------- /extension/debug/extension.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | console.log("Extension loaded"); 21 | 22 | var web2native_bridge = 'org.webpki.w2nb'; 23 | 24 | var ports = []; 25 | 26 | var BASE64URL = 27 | ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 28 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 29 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 30 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_']; 31 | 32 | function json2B64(jsonObject) { 33 | var string = JSON.stringify(jsonObject); 34 | var binArray = []; 35 | for (var n = 0; n < string.length; n++) { 36 | binArray.push(string.charCodeAt(n) & 0xFF); 37 | } 38 | var encoded = new String(); 39 | var i = 0; 40 | var modulo3 = binArray.length % 3; 41 | while (i < binArray.length - modulo3) { 42 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 43 | encoded += BASE64URL[((binArray[i++] << 4) & 0x30) | ((binArray[i] >>> 4) & 0x0F)]; 44 | encoded += BASE64URL[((binArray[i++] << 2) & 0x3C) | ((binArray[i] >>> 6) & 0x03)]; 45 | encoded += BASE64URL[binArray[i++] & 0x3F]; 46 | } 47 | if (modulo3 == 1) { 48 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 49 | encoded += BASE64URL[(binArray[i] << 4) & 0x30]; 50 | } 51 | else if (modulo3 == 2) { 52 | encoded += BASE64URL[(binArray[i] >>> 2) & 0x3F]; 53 | encoded += BASE64URL[((binArray[i++] << 4) & 0x30) | ((binArray[i] >>> 4) & 0x0F)]; 54 | encoded += BASE64URL[(binArray[i] << 2) & 0x3C]; 55 | } 56 | return encoded; 57 | } 58 | 59 | // Test that the native proxy is alive and kicking 60 | chrome.runtime.onStartup.addListener(function() { 61 | chrome.runtime.sendNativeMessage(web2native_bridge, {proxyVersion:"1.00"}, function(response) { 62 | if (response) { 63 | console.log("Extension successfully verified"); 64 | } else { 65 | alert('Web2Native Bridge library issue: ' + chrome.runtime.lastError.message); 66 | } 67 | }); 68 | }); 69 | 70 | function getPort(sender) { 71 | var port = ports[sender.tab.id]; 72 | if (!port) { 73 | alert('Missing port for: ' + sender.tab.id); 74 | } 75 | return port; 76 | } 77 | 78 | function getDisconnectPort(sender) { 79 | var port = getPort(sender); 80 | if (port) { 81 | delete ports[sender.tab.id]; 82 | } 83 | return port; 84 | } 85 | 86 | // When message is received from page send it to native 87 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { 88 | if(sender.id !== chrome.runtime.id || !sender.tab) { 89 | alert('Internal error'); 90 | return; 91 | } 92 | if (request.src === 'openreq') { 93 | var port = chrome.runtime.connectNative(web2native_bridge); 94 | ports[sender.tab.id] = port; 95 | port.onMessage.addListener(function(message) { 96 | console.debug('rec: ' + JSON.stringify(message)); 97 | chrome.tabs.sendMessage(sender.tab.id, {message:message,tabid:sender.tab.id}); 98 | }); 99 | port.onDisconnect.addListener(function() { 100 | console.debug('native disconnect'); 101 | getDisconnectPort(sender); 102 | chrome.tabs.sendMessage(sender.tab.id, {disconnect:true,tabid:sender.tab.id}); 103 | }); 104 | console.debug('connect: ' + JSON.stringify(request)); 105 | port.postMessage({url:request.origin, 106 | application:request.application, 107 | windowB64:json2B64(request.window), 108 | argumentsB64:json2B64(request.arguments)}); 109 | sendResponse({success:sender.tab.id}); 110 | } else if (request.src === 'webdis') { 111 | console.debug('web disconnect'); 112 | getDisconnectPort(sender).disconnect(); 113 | } else if (request.src === 'webmsg') { 114 | console.debug('web message'); 115 | getPort(sender).postMessage(request.message); 116 | } else { 117 | sendResponse({err:{}}); 118 | } 119 | }); 120 | -------------------------------------------------------------------------------- /proxy/src.java/org/webpki/w2nbproxy/ExtensionPositioning.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2016 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package org.webpki.w2nbproxy; 18 | 19 | import java.io.IOException; 20 | 21 | import org.webpki.json.JSONObjectReader; 22 | import org.webpki.json.JSONParser; 23 | 24 | import org.webpki.util.Base64URL; 25 | 26 | public class ExtensionPositioning { 27 | 28 | public class TargetRectangle { 29 | 30 | public double left; 31 | public double top; 32 | public double width; 33 | public double height; 34 | 35 | TargetRectangle(double left, double top, double width, double height) { 36 | this.left = left; 37 | this.top = top; 38 | this.width = width; 39 | this.height = height; 40 | } 41 | } 42 | 43 | JSONObjectReader positioningArguments; 44 | 45 | public static enum HORIZONTAL_ALIGNMENT {Left, Right, Center}; 46 | public static enum VERTICAL_ALIGNMENT {Top, Bottom, Center}; 47 | 48 | public static final String HORIZONTAL_ALIGNMENT_JSON = "horizontalAlignment"; 49 | public static final String VERTICAL_ALIGNMENT_JSON = "verticalAlignment"; 50 | 51 | public static final String TARGET_RECTANGLE_JSON = "targetRectangle"; 52 | 53 | public static final String TARGET_LEFT_JSON = "left"; 54 | public static final String TARGET_TOP_JSON = "top"; 55 | public static final String TARGET_WIDTH_JSON = "width"; 56 | public static final String TARGET_HEIGHT_JSON = "height"; 57 | 58 | public HORIZONTAL_ALIGNMENT horizontalAlignment; 59 | public VERTICAL_ALIGNMENT verticalAlignment; 60 | 61 | public TargetRectangle targetRectangle; // Optional (may be null) 62 | 63 | public ExtensionPositioning(String base64UrlEncodedArguments) throws IOException { 64 | positioningArguments = JSONParser.parse(Base64URL.decode(base64UrlEncodedArguments)); 65 | if (positioningArguments.hasProperty(HORIZONTAL_ALIGNMENT_JSON)) { 66 | horizontalAlignment = HORIZONTAL_ALIGNMENT.valueOf( 67 | positioningArguments.getString(HORIZONTAL_ALIGNMENT_JSON)); 68 | verticalAlignment = VERTICAL_ALIGNMENT.valueOf( 69 | positioningArguments.getString(VERTICAL_ALIGNMENT_JSON)); 70 | if (positioningArguments.hasProperty(TARGET_RECTANGLE_JSON)) { 71 | JSONObjectReader values = positioningArguments.getObject(TARGET_RECTANGLE_JSON); 72 | targetRectangle = new TargetRectangle(values.getDouble(TARGET_LEFT_JSON), 73 | values.getDouble(TARGET_TOP_JSON), 74 | values.getDouble(TARGET_WIDTH_JSON), 75 | values.getDouble(TARGET_HEIGHT_JSON)); 76 | } 77 | } 78 | positioningArguments.checkForUnread(); 79 | } 80 | 81 | public static String encode(HORIZONTAL_ALIGNMENT horizontalAlignment, 82 | VERTICAL_ALIGNMENT verticalAlignment, 83 | String optionalTargetElementId) { 84 | return "setExtensionPosition('" + horizontalAlignment.toString() + 85 | "', '" + verticalAlignment.toString() + "'" + 86 | (optionalTargetElementId == null ? "" : ", '" + optionalTargetElementId + "'") + ")"; 87 | } 88 | 89 | public static final String SET_EXTENSION_POSITION_FUNCTION_TEXT = 90 | "function setExtensionPosition(hAlign, vAlign, optionalId) {\n" + 91 | " var result = {" + HORIZONTAL_ALIGNMENT_JSON + ":hAlign, " + 92 | VERTICAL_ALIGNMENT_JSON + ":vAlign}\n" + 93 | " if (optionalId) {\n" + 94 | " var input = document.getElementById(optionalId).getBoundingClientRect();\n" + 95 | " var rectangle = {};\n" + 96 | " rectangle." + TARGET_LEFT_JSON + " = input." + TARGET_LEFT_JSON + ";\n" + 97 | " rectangle." + TARGET_TOP_JSON + " = input." + TARGET_TOP_JSON + ";\n" + 98 | " rectangle." + TARGET_WIDTH_JSON + " = input." + TARGET_WIDTH_JSON + ";\n" + 99 | " rectangle." + TARGET_HEIGHT_JSON + " = input." + TARGET_HEIGHT_JSON + ";\n" + 100 | " result." + TARGET_RECTANGLE_JSON + " = rectangle;\n" + 101 | " }\n" + 102 | " return result;\n" + 103 | "}\n"; 104 | 105 | @Override 106 | public String toString() { 107 | return positioningArguments.toString(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web2Native Bridge - Uniting the "Web" and "App" worlds 2 | 3 |
Note: this is a system in development, the specification may change anytime without notice
4 | 5 | This repository contains all code for building and testing an emulation of 6 | the Web2Native Bridge concept 7 | (https://cyberphone.github.io/doc/web/web2native-bridge.pdf) 8 | using the Google **Chrome** and Mozilla **Firefox** desktop browsers. It also runs on the Open Source **Chromium** browser. 9 | 10 | The emulator code exploits Chrome's native messaging (https://developer.chrome.com/extensions/nativeMessaging) 11 | featured in a single universal Chrome/Firefox extension. 12 | 13 | Applications callable by the Web2Native Bridge emulator must be written in Java and stored in a for the purpose 14 | dedicated directory. 15 | 16 | ## API 17 | The Web2Native Bridge emulator extends the navigator object by a *single* method
18 | nativeConnect('*Name of target application*' [, *optionalArgument*]) which 19 | returns a JavaScript Promise to a port object. 20 | 21 | The port object supports the following methods and events: 22 | * postMessage(*message*) 23 | * disconnect() 24 | * addMessageListener(function(*message*)) 25 | * addDisconnectListener(function()) 26 | 27 | *optionalArgument* and *message* **must** be valid JSON-serializable JavaScript objects. 28 | 29 | An example which could be hosted in an ordinary (*non-privileged*) web page: 30 | ```javascript 31 | navigator.nativeConnect('com.example.myapp').then(function(port) { 32 | 33 | port.addMessageListener(function(message) { 34 | // We got a message from the native application... 35 | }); 36 | 37 | port.addDisconnectListener(function() { 38 | // Native application disconnected... 39 | }); 40 | 41 | port.postMessage({greeting:'Native app, how are you doing?'}); 42 | // Note: JavaScript serialization makes the above a genuine JSON object 43 | 44 | port.disonnect(); // Not much of a conversation going on here... 45 | 46 | }, function(err) { 47 | console.debug(err); 48 | }); 49 | ``` 50 | The argument to nativeConnect holds the name of the specifically adapted local application to invoke. The current scheme uses a Java-inspired dotted path pointing to a subdirectory and JAR-application having this name. 51 | 52 | ## Manifest 53 | For specifying access to native applications there **must** be a JSON-formatted *manifest* file associated with each application. 54 | The following *manifest* provides universal access to an application: 55 | ```json 56 | { 57 | "callableFrom": ["*://*/*", "file:///*"] 58 | } 59 | ``` 60 | A more restrictive *manifest* could limit access to a single domain and https operation: 61 | ```json 62 | { 63 | "callableFrom": ["https://example.com/*", "https://*.example.com/*"] 64 | } 65 | ``` 66 | 67 | ## Architecture 68 | The Web2Native Bridge emulator always invokes a central proxy located at proxy/install/w2nb-proxy.
69 | 70 | The proxy in turn dispatches a call to the specific target application located at
71 | proxy/install/apps/*dottedpath*/*dottedpath*.jar. 72 | 73 | The mandatory *manifest* file is stored at
74 | proxy/install/apps/*dottedpath*/manifest.json. 75 | 76 | Common Java libraries may be stored in proxy/install/libs. 77 | 78 | For debugging purposes there is also a logging system writing data in proxy/install/logs. 79 | 80 | All local I/O between the browser, proxy and the callable applications 81 | is performed through stdin and stdout. 82 | 83 | ## Native Application Interface 84 | Native applications (in the prototype Java applications hosted in JAR-files) are called as follows: 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
args[0]Absolute path to the proxy/install directory
args[1]Application name (dotted path)
args[2]URL of calling web page
args[3]Coordinates of calling web page
args[4]Custom invocation data (OptionalArgument)
args[5...]Chrome's Native Messaging arguments
93 | For detailed information about the format of these fields, turn to the code :-) 94 | 95 | ## Installation 96 | ### Prerequisites 97 | * You need to have **Java SE version 8** installed to run the Web2Native Bridge emulator 98 | * OS/X and Linux installations presume that **clang** respectively **g++** is available 99 | * Clone the **web2native-bridge** master repository or just download the ZIP via GitHub to any free directory 100 | 101 | Note: If you are using Oracle Java you must install the **Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files** as well. 102 | 103 | ### Chrome/Chromium specific steps 104 | 1. Start a terminal window and move to proxy/install. Then run the install-proxy script that suits your platform 105 | 2. Install the Web2Native Bridge browser extension from the Chrome Web Store: 106 | https://chrome.google.com/webstore/detail/web2native-bridge-emulato/jphfmfbdedghfhhjijaogeloiehomfni 107 | 3. In Chrome, go to Settings->Extensions and check "Allow access to file URLs" for the Web2Native Bridge extension 108 | 109 | ### Firefox specific steps 110 | 1. Start a terminal window and move to firefox/install. Then run the install-proxy script that suits your platform 111 | 2. Install the Web2Native Bridge browser extension from the file firefox/install/xpi/web2native_bridge_emulator-1.0.xpi using the Firefox menu option: *Add-ons->Extensions->Install Add-on from file*. 112 | 113 | ### Testing the installation 114 | Now you can try the two sample applications (see next sections) since they are installed by default. 115 | 116 | Please don't hesitate contacting me if you run into problems during installation or execution of the emulator! 117 | 118 | ## Basic Sample Application 119 | The HTML file sample1/demo/sample1.html does approximately 120 | the same thing as the application depicted in 121 | http://www.cnet.com/news/google-paves-over-hole-left-by-chrome-plug-in-ban/ 122 | albeit with a few significant enhancements: 123 | * The sample application is invoked by an ordinary web page 124 | * The Web2Native Bridge browser extension is fully generic and can support any number of very different applications 125 | * The Web2Native Bridge adds positioning support enabling alignment UI-wise with the web 126 | 127 | The native part of the sample application resides in proxy/install/apps/org.webpki.w2nb.sample1/org.webpki.w2nb.sample1.jar. 128 | 129 | ## Single Page Application 130 | Although not a design goal, the Web2Native Bridge API is also compliant with the SPA concept:
131 | https://en.wikipedia.org/wiki/Single-page_application 132 | 133 | ## Security Considerations 134 | Since an emulator *by definition* isn't the "real thing" some limitations apply. That is, the Web2Native Bridge 135 | emulator is *not intended for production* since it doesn't support the following security measures: 136 | * Native application vetting infrastructure. An improperly designed native message extension could enable web access to the entire computer! 137 | * HTTPS information 138 | * Site-blocking support and associated administration 139 | 140 | Although not entirely comforting, Chrome's native messaging framework also lacks these qualities... 141 | 142 | In addition, the scheme injects code in every web page visited which is a core "feature" of Chrome extensions 143 | slowing down execution. It is probably wise disabling the extension (using Chrome *settings*) when not using it. 144 | -------------------------------------------------------------------------------- /sample1/src/org/webpki/w2nb/sample1/NativeClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2016 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package org.webpki.w2nb.sample1; 18 | 19 | import java.awt.Container; 20 | import java.awt.Dimension; 21 | import java.awt.Font; 22 | import java.awt.GridBagConstraints; 23 | import java.awt.GridBagLayout; 24 | import java.awt.Toolkit; 25 | import java.awt.Insets; 26 | 27 | import java.awt.event.ActionEvent; 28 | import java.awt.event.ActionListener; 29 | import java.awt.event.WindowEvent; 30 | import java.awt.event.WindowAdapter; 31 | 32 | import java.io.IOException; 33 | 34 | import java.util.GregorianCalendar; 35 | 36 | import java.util.logging.Logger; 37 | import java.util.logging.Level; 38 | 39 | import javax.swing.JButton; 40 | import javax.swing.JDialog; 41 | import javax.swing.JFrame; 42 | import javax.swing.JLabel; 43 | import javax.swing.JScrollPane; 44 | import javax.swing.JTextArea; 45 | import javax.swing.JTextField; 46 | 47 | import org.webpki.json.JSONObjectWriter; 48 | 49 | import org.webpki.util.ISODateTime; 50 | 51 | import org.webpki.w2nbproxy.BrowserWindow; 52 | import org.webpki.w2nbproxy.StdinJSONPipe; 53 | import org.webpki.w2nbproxy.StdoutJSONPipe; 54 | import org.webpki.w2nbproxy.LoggerConfiguration; 55 | 56 | 57 | //Simple Web2Native Bridge emulator application 58 | 59 | class ApplicationFrame extends Thread { 60 | StdinJSONPipe stdin = new StdinJSONPipe(); 61 | StdoutJSONPipe stdout = new StdoutJSONPipe(); 62 | JTextArea textArea; 63 | JTextField sendText; 64 | 65 | ApplicationFrame(Container pane) { 66 | int fontSize = Toolkit.getDefaultToolkit().getScreenResolution() / 7; 67 | JLabel msgLabel = new JLabel("Messages:"); 68 | Font font = msgLabel.getFont(); 69 | boolean macOS = System.getProperty("os.name").toLowerCase().contains("mac"); 70 | if (font.getSize() > fontSize || macOS) { 71 | fontSize = font.getSize(); 72 | } 73 | int stdInset = fontSize/3; 74 | msgLabel.setFont(new Font(font.getFontName(), font.getStyle(), fontSize)); 75 | pane.setLayout(new GridBagLayout()); 76 | GridBagConstraints c = new GridBagConstraints(); 77 | c.weightx = 0.0; 78 | c.anchor = GridBagConstraints.WEST; 79 | c.fill = GridBagConstraints.NONE; 80 | c.gridx = 0; 81 | c.gridy = 0; 82 | c.gridwidth = 2; 83 | c.insets = new Insets(stdInset, stdInset, stdInset, stdInset); 84 | pane.add(msgLabel, c); 85 | 86 | textArea = new JTextArea(); 87 | textArea.setRows(20); 88 | textArea.setFont(new Font("Courier", Font.PLAIN, fontSize)); 89 | textArea.setEditable(false); 90 | JScrollPane scrollPane = new JScrollPane(textArea); 91 | c.fill = GridBagConstraints.BOTH; 92 | c.weightx = 1.0; 93 | c.weighty = 1.0; 94 | c.gridwidth = 2; 95 | c.gridy = 1; 96 | c.insets = new Insets(0, stdInset, 0, stdInset); 97 | pane.add(scrollPane , c); 98 | 99 | JButton sendBut = new JButton("\u00a0\u00a0\u00a0Send\u00a0\u00a0\u00a0"); 100 | sendBut.setFont(new Font(font.getFontName(), font.getStyle(), fontSize)); 101 | sendBut.addActionListener(new ActionListener() { 102 | @Override 103 | public void actionPerformed(ActionEvent event) { 104 | try { 105 | update(stdout.writeJSONObject(new JSONObjectWriter().setString("native", 106 | sendText.getText()))); 107 | } catch (IOException e) { 108 | NativeClient.logger.log(Level.SEVERE, "Writing", e); 109 | System.exit(3); 110 | } 111 | } 112 | }); 113 | c.fill = GridBagConstraints.NONE; 114 | c.weightx = 0.0; 115 | c.weighty = 0.0; 116 | c.gridwidth = 1; 117 | c.gridy = 2; 118 | c.insets = new Insets(stdInset, stdInset, stdInset, 0); 119 | pane.add(sendBut, c); 120 | 121 | sendText = new JTextField(50); 122 | sendText.setFont(new Font("Courier", Font.PLAIN, fontSize)); 123 | c.fill = GridBagConstraints.HORIZONTAL; 124 | c.gridx = 1; 125 | c.insets = new Insets(stdInset, stdInset, stdInset, stdInset); 126 | pane.add(sendText, c); 127 | } 128 | 129 | void update(String text) { 130 | String localTime = ISODateTime.formatDateTime(new GregorianCalendar(), ISODateTime.LOCAL_NO_SUBSECONDS); 131 | textArea.setText(localTime.substring(0, 10) + " " + localTime.substring(11, 19) + 132 | " " + text + "\n" + textArea.getText()); 133 | NativeClient.logger.info(text); 134 | } 135 | 136 | @Override 137 | public void run() { 138 | while (true) { 139 | try { 140 | stdin.readJSONObject(); // Just syntax checking used in our crude sample 141 | update(stdin.getJSONString()); 142 | } catch (IOException e) { 143 | NativeClient.logger.log(Level.SEVERE, "Reading", e); 144 | System.exit(3); 145 | } 146 | } 147 | } 148 | } 149 | 150 | public class NativeClient { 151 | static Logger logger = Logger.getLogger("MyLog"); 152 | 153 | public static void main(String[] args) { 154 | LoggerConfiguration.init(logger, args); 155 | for (int i = 0; i < args.length; i++) { 156 | logger.info("ARG[" + i + "]=" + args[i]); 157 | } 158 | 159 | BrowserWindow browserWindow = null; 160 | try { 161 | browserWindow = new BrowserWindow(args[3]); 162 | logger.info("Browser window: " + browserWindow); 163 | } catch (Exception e) { 164 | logger.log(Level.SEVERE, "nativeConnect argument errors", e); 165 | } 166 | JDialog frame = new JDialog(new JFrame(), "W2NB - Sample #1 [" + args[2] + "]"); 167 | ApplicationFrame md = new ApplicationFrame(frame.getContentPane()); 168 | frame.pack(); 169 | 170 | if (browserWindow.screenHeight == 0) { 171 | frame.setLocationRelativeTo(null); // tapConnect invocation 172 | } else { 173 | // Put the extension window on top of the upper right of the calling (browser)window 174 | // The alignment varies a bit between platforms :-( 175 | Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); 176 | Dimension extensionWindow = frame.getSize(); 177 | double factor = screenDimension.height / browserWindow.screenHeight; 178 | double gutter = (browserWindow.outerWidth - browserWindow.innerWidth) / 2; 179 | double x = browserWindow.x + gutter; 180 | x += browserWindow.innerWidth - extensionWindow.width / factor; 181 | double y = browserWindow.y + browserWindow.outerHeight - browserWindow.innerHeight - gutter; 182 | frame.setLocation((int)(x * factor), (int)(y * factor)); 183 | } 184 | 185 | frame.setAlwaysOnTop(true); 186 | 187 | frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 188 | frame.addWindowListener(new WindowAdapter() { 189 | @Override 190 | public void windowClosing(WindowEvent event) { 191 | System.exit(0); 192 | } 193 | }); 194 | frame.setVisible(true); 195 | md.start(); 196 | } 197 | } -------------------------------------------------------------------------------- /proxy/src.cpp/w2nb-proxy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2006-2015 WebPKI.org (http://webpki.org). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////////////////// 19 | // w2nb-proxy.cpp // 20 | // // 21 | // This program emulates the proxy required on the native side by the Web2Native Bridge // 22 | // while still only relying on Chrome's Native Messaging. // 23 | // // 24 | // Note: The security features provided by the Web2Native Bridge are NOT supported! // 25 | // // 26 | // Author: Anders Rundgren // 27 | ////////////////////////////////////////////////////////////////////////////////////////// 28 | 29 | #ifdef WIN32 30 | #define FILE_SEPARATOR '\\' 31 | #define _CRT_SECURE_NO_WARNINGS 32 | #define JAVA_PLAF " -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel" 33 | #define JAVA_LOG " \"-Djava.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n\"" 34 | #else 35 | #define FILE_SEPARATOR '/' 36 | #define JAVA_LOG " \"-Djava.util.logging.SimpleFormatter.format=%1\\$tY-%1\\$tm-%1\\$td %1\\$tH:%1\\$tM:%1\\$tS %4\\$s %2\\$s %5\\$s%6\\$s%n\"" 37 | #define JAVA_PLAF "" 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #define PROXY_VERSION "1.00" 46 | 47 | #define MANIFEST_SIZE 1000 48 | 49 | static char *res; 50 | 51 | static FILE* logFile; 52 | 53 | static void loggedError(const char* format, ...) { 54 | if (logFile) { 55 | va_list args; 56 | va_start(args, format); 57 | vfprintf(logFile, format, args); 58 | va_end(args); 59 | fclose(logFile); 60 | } 61 | exit(EXIT_FAILURE); 62 | } 63 | 64 | // "Budget" JSON parser 65 | static char* getJSONProperty(char *property, char beginChar, char endChar) { 66 | char buffer[100] = "\""; 67 | strcat(buffer, property); 68 | strcat(buffer, "\":"); 69 | char *start = strstr(res, buffer); 70 | if (!start) { 71 | loggedError("Property %s missing\nJSON=\n%s", property, res); 72 | } 73 | start += strlen(buffer); 74 | if (*start++ != beginChar) { 75 | loggedError("Expected: %c\nJSON=\n%s", beginChar, res); 76 | } 77 | char *end = strchr(start, endChar); 78 | if (!end) { 79 | loggedError("Expected: %c\nJSON=\n%s", endChar, res); 80 | } 81 | int length = end - start + 1; 82 | char *value = new char[length--]; 83 | strncpy(value, start, length); 84 | value[length] = 0; 85 | return value; 86 | } 87 | 88 | static char* getJSONString(char *property) { 89 | return getJSONProperty(property, '\"', '\"'); 90 | } 91 | 92 | static char* getJSONArray(char *property) { 93 | return getJSONProperty(property, '[', ']'); 94 | } 95 | 96 | static bool matching(char* accessDescriptor, char* calledBy) { 97 | while (*accessDescriptor) { 98 | if (*accessDescriptor == '*') { 99 | accessDescriptor++; 100 | while (*calledBy != *accessDescriptor) { 101 | if (*calledBy) { 102 | calledBy++; 103 | } else { 104 | return false; 105 | } 106 | } 107 | } else { 108 | if (*calledBy != *accessDescriptor) { 109 | return false; 110 | } 111 | accessDescriptor++; 112 | calledBy++; 113 | } 114 | } 115 | return !*calledBy; 116 | } 117 | 118 | static void checkAccess(char* appPath, char* calledBy) { 119 | char manifest[MANIFEST_SIZE + 1]; 120 | int c; 121 | int index = 0; 122 | bool quote = false; 123 | 124 | strcat(appPath, "manifest.json"); 125 | FILE* manifestFile = fopen(appPath, "r"); 126 | if (!manifestFile) { 127 | loggedError("Error: 'manifest.json' not found!"); 128 | } 129 | while ((c = fgetc(manifestFile)) != EOF) { 130 | if (index == MANIFEST_SIZE) { 131 | loggedError("Error: manifest bigger than: %d", MANIFEST_SIZE); 132 | } 133 | if (c == '\"') { 134 | quote = !quote; 135 | } 136 | else if (c == '\\') { 137 | if (!quote || fgetc(manifestFile) != '\\') { 138 | loggedError("Error: unexpected \\ in manifest"); 139 | } 140 | } 141 | else if (!quote && (c == ' ' || c == '\n' || c == '\t' || c == '\r')) { 142 | continue; 143 | } 144 | manifest[index++] = (char)c; 145 | } 146 | manifest[index] = (char)0; 147 | fclose(manifestFile); 148 | res = manifest; 149 | char* callableFrom = getJSONArray("callableFrom"); 150 | index = 0; 151 | int arrayLength = strlen(callableFrom) - 4; 152 | bool next = false; 153 | while (index < arrayLength) { 154 | if (next) { 155 | if (callableFrom[index++] != ',') { 156 | loggedError("Error: missing ',' in manifest"); 157 | } 158 | } 159 | next = true; 160 | if (callableFrom[index++] != '\"') { 161 | loggedError("Error: missing '\"' in manifest"); 162 | } 163 | char* startString = callableFrom + index; 164 | char* endString = strchr(startString, '\"'); 165 | if (!endString) { 166 | loggedError("Error: missing '\"' in manifest"); 167 | } 168 | *endString = 0; 169 | if (matching(startString, calledBy)) { 170 | return; 171 | } 172 | index += strlen(startString) + 1; 173 | } 174 | loggedError("Error: not allowed: %s", calledBy); 175 | } 176 | 177 | int main(int argc, char *argv[]) { 178 | // Reading an initial JSON message which can be of two kinds: 179 | // 1. Proxy verification which consists of an object {"proxyVersion":"n.nn"} 180 | // 2. Java application call which consists of an object ("application":"dotted-path", 181 | // "url":"invocation-url", 182 | // "windowB64":"base64url-encoded-json-object", 183 | // "argumentsB64":"base64url-encoded-json-object"} 184 | 185 | // Chrome presumes message length in native order. Not very cool. 186 | // The following code therefore only runs on little-endian CPUs. 187 | int length = 0; 188 | for (int i = 0; i < 32; i += 8) { 189 | length += getchar() << i; 190 | } 191 | 192 | // We expect a tiny JSON object 193 | if (length > 10000) { 194 | exit(EXIT_FAILURE); 195 | } 196 | 197 | // OK. Read the JSON string 198 | res = new char[length + 1]; 199 | for (int n = 0; n < length; n++) { 200 | res[n] = getchar(); 201 | } 202 | res[length] = 0; 203 | 204 | // Are we doing proxy verification? 205 | if (strstr(res, "\"proxyVersion\":")) { 206 | if (strcmp(PROXY_VERSION, getJSONString("proxyVersion"))) { 207 | exit(EXIT_FAILURE); 208 | } 209 | char zeroObject[] = { 2,0,0,0,'{','}' }; 210 | for (int n = 0; n < sizeof(zeroObject); n++) { 211 | putchar(zeroObject[n]); 212 | } 213 | fclose(stdout); 214 | exit(EXIT_SUCCESS); 215 | } 216 | 217 | // No, we are executing a Java target application 218 | char cmd[2000] = "java" JAVA_LOG JAVA_PLAF " -jar \""; 219 | char path[500]; 220 | strcpy(path, argv[0]); 221 | int i = strlen(path); 222 | while (path[--i] != FILE_SEPARATOR) 223 | ; 224 | path[i] = 0; 225 | char fs[] = { FILE_SEPARATOR,0 }; 226 | 227 | char *application = getJSONString("application"); 228 | 229 | // Check that the caller isn't trying to get outside the sandbox 230 | i = 0; 231 | char c; 232 | while (c = application[i++]) { 233 | if ((c > 'Z' || c < 'A') && (c > 'z' || c < 'a') && (c > '9' || c < '0') && c != '.' && c != '_') { 234 | exit(EXIT_FAILURE); 235 | } 236 | } 237 | 238 | // Create a path to the application directory including / 239 | char appPath[500]; 240 | strcpy(appPath, path); 241 | strcat(appPath, fs); 242 | strcat(appPath, "apps"); 243 | strcat(appPath, fs); 244 | strcat(appPath, application); 245 | strcat(appPath, fs); 246 | 247 | // The actual JAR to call 248 | strcat(cmd, appPath); 249 | strcat(cmd, application); 250 | strcat(cmd, ".jar\" \""); 251 | 252 | // Parameters to called Java program 253 | 254 | // args[0] => Full path to proxy/install 255 | strcat(cmd, path); 256 | strcat(cmd, "\" "); 257 | 258 | // args[1] => Dotted path (=application name) 259 | strcat(cmd, application); 260 | strcat(cmd, " \""); 261 | 262 | // args[2] => invoking URL 263 | char* calledBy = getJSONString("url"); 264 | strcat(cmd, calledBy); 265 | strcat(cmd, "\" "); 266 | 267 | // args[3] => Invoking window core data 268 | strcat(cmd, getJSONString("windowB64")); 269 | strcat(cmd, " "); 270 | 271 | // args[4] => Optional arguments to navigator.nativeConnect 272 | strcat(cmd, getJSONString("argumentsB64")); 273 | 274 | // args[5..n] => Chrome standard arguments 275 | for (int i = 1; i < argc; i++) { 276 | strcat(cmd, " "); 277 | strcat(cmd, argv[i]); 278 | } 279 | 280 | // Log file to last executed command 281 | char fileName[500]; 282 | strcpy(fileName, path); 283 | strcat(fileName, fs); 284 | strcat(fileName, "logs"); 285 | strcat(fileName, fs); 286 | strcat(fileName, "w2nb-proxy-init.log"); 287 | logFile = fopen(fileName, "w"); 288 | fprintf(logFile, "commmand: %s\n", cmd); 289 | 290 | // Read the manifest and verify that the caller is legitimate before calling application 291 | checkAccess(appPath, calledBy); 292 | 293 | // This is not the recommended solution for POSIX-compliant systems but hey, this is a PoC... 294 | int returnCode = system(cmd); 295 | if (returnCode) { 296 | fprintf(logFile, "Error: '%s' %d\n", strerror(returnCode), returnCode); 297 | } 298 | fclose(logFile); 299 | return 0; 300 | } 301 | -------------------------------------------------------------------------------- /AR2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | --------------------------------------------------------------------------------