mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-07-03 14:07:39 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3ff89855f | |||
| 1c4eabd247 | |||
| 2753ca4807 | |||
| 4713151b7b | |||
| 06b0f46a49 | |||
| cf1aed1ff1 |
@@ -2,4 +2,3 @@ deploy/data/windows/x64/tap/windows_7/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x64/tap/windows_10/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x32/tap/windows_7/OemVista.inf eol=crlf
|
||||
deploy/data/windows/x32/tap/windows_10/OemVista.inf eol=crlf
|
||||
client/3rd/* linguist-vendored
|
||||
|
||||
@@ -291,11 +291,6 @@ jobs:
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
|
||||
- name: 'Install GO'
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
|
||||
+4
-25
@@ -6,7 +6,7 @@
|
||||
url = https://github.com/WireGuard/wireguard-apple
|
||||
[submodule "client/3rd/OpenVPNAdapter"]
|
||||
path = client/3rd/OpenVPNAdapter
|
||||
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
|
||||
url = https://github.com/ss-abramchuk/OpenVPNAdapter.git
|
||||
[submodule "client/3rd/ShadowPath"]
|
||||
path = client/3rd/ShadowPath
|
||||
url = https://github.com/qman9501/ShadowPath
|
||||
@@ -28,33 +28,12 @@
|
||||
[submodule "client/3rd/zlib"]
|
||||
path = client/3rd/zlib
|
||||
url = https://github.com/madler/zlib.git
|
||||
[submodule "deploy/amnezia-ios-certificates"]
|
||||
path = deploy/amnezia-ios-certificates
|
||||
url = https://github.com/amnezia-vpn/amnezia-ios-certificates.git
|
||||
[submodule "client/3rd/SortFilterProxyModel"]
|
||||
path = client/3rd/SortFilterProxyModel
|
||||
url = https://github.com/mitchcurtis/SortFilterProxyModel.git
|
||||
[submodule "client/android/cpp/openvpn3"]
|
||||
path = client/android/cpp/openvpn3
|
||||
url = https://github.com/amnezia-vpn/openvpn3.git
|
||||
[submodule "client/android/cpp/asio"]
|
||||
path = client/android/cpp/asio
|
||||
url = https://github.com/chriskohlhoff/asio
|
||||
[submodule "client/android/cpp/lz4"]
|
||||
path = client/android/cpp/lz4
|
||||
url = https://github.com/lz4/lz4.git
|
||||
[submodule "client/android/cpp/mbedtls"]
|
||||
path = client/android/cpp/mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls.git
|
||||
[submodule "client/android/cpp/openvpn"]
|
||||
path = client/android/cpp/openvpn
|
||||
url = https://github.com/schwabe/openvpn.git
|
||||
[submodule "client/android/cpp/openssl"]
|
||||
path = client/android/cpp/openssl
|
||||
url = https://github.com/schwabe/platform_external_openssl.git
|
||||
[submodule "client/android/cpp/cloak"]
|
||||
path = client/android/cpp/cloak
|
||||
url = https://github.com/amnezia-vpn/Cloak
|
||||
[submodule "client/android/cpp/lzo"]
|
||||
path = client/android/cpp/lzo
|
||||
url = https://github.com/amnezia-vpn/lzo.git
|
||||
[submodule "client/3rd/mbedtls"]
|
||||
path = client/3rd/mbedtls
|
||||
url = https://github.com/Mbed-TLS/mbedtls.git
|
||||
|
||||
Vendored
-47
@@ -1,47 +0,0 @@
|
||||
FROM gitpod/workspace-full-vnc
|
||||
|
||||
USER gitpod
|
||||
|
||||
RUN sudo apt-get -q update \
|
||||
&& sudo apt-get install -yq \
|
||||
build-essential \
|
||||
libgl1-mesa-dev \
|
||||
libgstreamer-gl1.0-0 \
|
||||
libpulse-dev \
|
||||
libsecret-1-dev \
|
||||
libxcb-glx0 \
|
||||
libxcb-icccm4 \
|
||||
libxcb-image0 \
|
||||
libxcb-keysyms1 \
|
||||
libxcb-randr0 \
|
||||
libxcb-render-util0 \
|
||||
libxcb-render0 \
|
||||
libxcb-shape0 \
|
||||
libxcb-shm0 \
|
||||
libxcb-sync1 \
|
||||
libxcb-util1 \
|
||||
libxcb-xfixes0 \
|
||||
libxcb-xinerama0 \
|
||||
libxcb1 \
|
||||
libxkbcommon-dev \
|
||||
libxkbcommon-x11-0 \
|
||||
libxcb-xkb-dev \
|
||||
p7zip-full \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN sudo pip3 install aqtinstall
|
||||
|
||||
ARG QT_VERSION=6.4.1
|
||||
ARG QT_ARCH=gcc_64
|
||||
|
||||
ARG QT_DIR=/opt/qt
|
||||
RUN sudo aqt install-qt --outputdir ${QT_DIR} linux desktop ${QT_VERSION} ${QT_ARCH} --modules \
|
||||
qtremoteobjects \
|
||||
qt5compat \
|
||||
qtshadertools
|
||||
ENV QT_BIN_DIR=${QT_DIR}/${QT_VERSION}/${QT_ARCH}/bin
|
||||
|
||||
ARG QIF_VERSION=4.5
|
||||
ARG QIF_DIR=/opt/qif
|
||||
RUN sudo aqt install-tool --outputdir ${QIF_DIR} linux desktop tools_ifw
|
||||
ENV QIF_BIN_DIR=${QIF_DIR}/Tools/QtInstallerFramework/${QIF_VERSION}/bin
|
||||
@@ -1,8 +0,0 @@
|
||||
tasks:
|
||||
- init: >-
|
||||
deploy/build_linux.sh
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
vscode:
|
||||
extensions:
|
||||
- llvm-vs-code-extensions.vscode-clangd
|
||||
+1
-1
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
|
||||
project(${PROJECT} VERSION 3.0.7.4
|
||||
project(${PROJECT} VERSION 3.0.7.1
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
HOMEPAGE_URL "https://amnezia.org/"
|
||||
)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Amnezia VPN
|
||||
## _The best client for self-hosted VPN_
|
||||
|
||||
[](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
|
||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
||||
[]
|
||||
|
||||
Amnezia is a VPN client with the key feature of deploying your own VPN server on you virtual server.
|
||||
|
||||
|
||||
Submodule client/3rd/OpenVPNAdapter updated: 7b4046faf3...0e2db0baa0
+14
-11
@@ -48,8 +48,7 @@ endif()
|
||||
qt_standard_project_setup()
|
||||
|
||||
if(IOS)
|
||||
#execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/scripts/run-build-cloak.sh)
|
||||
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
|
||||
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/scripts/openvpn.sh args
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
|
||||
@@ -214,11 +213,7 @@ if(APPLE)
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||
add_compile_definitions(MVPN_MACOS)
|
||||
|
||||
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
||||
set(MACOSX_BUNDLE_ICON_FILE app.icns)
|
||||
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
set(SOURCES ${SOURCES} ${ICON_FILE})
|
||||
# ICON = $$PWD/images/app.icns
|
||||
|
||||
find_library(FW_COCOA Cocoa)
|
||||
find_library(FW_APPLICATIONSERVICES ApplicationServices)
|
||||
@@ -318,6 +313,7 @@ if(IOS)
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ios_vpnprotocol.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/iosnotificationhandler.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/json.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/bigint.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/bigintipv6addr.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/ipaddress.h
|
||||
@@ -329,6 +325,7 @@ if(IOS)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ios_vpnprotocol.mm
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/iosnotificationhandler.mm
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/json.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/iosglue.mm
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/ipaddress.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/ipaddressrange.cpp
|
||||
@@ -365,7 +362,7 @@ if(IOS)
|
||||
|
||||
target_include_directories(${PROJECT} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(BUILD_ID ${A_PROJECT_BUILD})
|
||||
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
|
||||
@@ -376,12 +373,12 @@ if(IOS)
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${CMAKE_PROJECT_VERSION}-${BUILD_ID}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION}"
|
||||
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_LIST_DIR}/ios/app/main.entitlements"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}"
|
||||
XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}"
|
||||
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
|
||||
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN"
|
||||
@@ -517,6 +514,12 @@ if(ANDROID)
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/wireguard/${abi}/libwg.so
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/wireguard/${abi}/libwg-go.so
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/wireguard/${abi}/libwg-quick.so
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/openvpn/${abi}/libjbcrypto.so
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/openvpn/${abi}/libopenvpn.so
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/openvpn/${abi}/libopvpnutil.so
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/openvpn/${abi}/libovpn3.so
|
||||
${CMAKE_CURRENT_LIST_DIR}/android/lib/openvpn/${abi}/libovpnexec.so
|
||||
)
|
||||
endforeach()
|
||||
|
||||
|
||||
+10
-27
@@ -11,8 +11,6 @@ buildscript {
|
||||
streamsupportVersion = '1.7.0'
|
||||
threetenabpVersion = '1.1.1'
|
||||
groupName = 'org.amnezia.vpn'
|
||||
minSdkVer = '24'
|
||||
cmakeMinVersion = "3.25.0+"
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -22,8 +20,6 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.google.gms:google-services:4.3.2'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1'
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0'
|
||||
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.8.0'
|
||||
@@ -40,8 +36,9 @@ apply plugin: 'kotlin-kapt'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation group: 'org.json', name: 'json', version: '20220924'
|
||||
implementation 'androidx.core:core-ktx:1.9.0'
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
|
||||
implementation "androidx.security:security-crypto:1.1.0-alpha03"
|
||||
@@ -65,13 +62,6 @@ dependencies {
|
||||
|
||||
def camerax_ml_version = "1.2.0-beta02"
|
||||
def ml_kit_version = "17.0.3"
|
||||
def work_version = "2.7.1"
|
||||
|
||||
implementation "com.google.android.gms:play-services-oss-licenses:17.0.0"
|
||||
implementation "com.google.code.gson:gson:2.10.1"
|
||||
implementation "com.google.firebase:firebase-analytics-ktx:21.2.0"
|
||||
implementation "com.google.firebase:firebase-crashlytics:18.3.3"
|
||||
implementation "androidx.work:work-runtime-ktx:${work_version}"
|
||||
implementation("androidx.camera:camera-mlkit-vision:${camerax_ml_version}")
|
||||
implementation("com.google.mlkit:barcode-scanning:${ml_kit_version}")
|
||||
}
|
||||
@@ -160,10 +150,7 @@ android {
|
||||
minifyEnabled false
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version cmakeMinVersion
|
||||
arguments "-DANDROID_PACKAGE_NAME=${groupName}",
|
||||
"-DGRADLE_USER_HOME=${project.gradle.gradleUserHomeDir}",
|
||||
"-DANDROID_PLATFORM=${minSdkVer}"
|
||||
arguments "-DANDROID_PACKAGE_NAME=${groupName}", "-DGRADLE_USER_HOME=${project.gradle.gradleUserHomeDir}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,10 +160,7 @@ android {
|
||||
minifyEnabled false
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version cmakeMinVersion
|
||||
arguments "-DANDROID_PACKAGE_NAME=${groupName}",
|
||||
"-DGRADLE_USER_HOME=${project.gradle.gradleUserHomeDir}",
|
||||
"-DANDROID_PLATFORM=${minSdkVer}"
|
||||
arguments "-DANDROID_PACKAGE_NAME=${groupName}", "-DGRADLE_USER_HOME=${project.gradle.gradleUserHomeDir}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,12 +172,11 @@ android {
|
||||
// }
|
||||
// }
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version cmakeMinVersion
|
||||
path "${projectDir}/cpp/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
// externalNativeBuild {
|
||||
// cmake {
|
||||
// path 'openvpn/src/main/cpp/CMakeLists.txt'
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(AmneziaVPN)
|
||||
# Git version string
|
||||
|
||||
include(GetGitRevisionDescription.cmake)
|
||||
git_describe(OPENVPN2_GIT "${CMAKE_CURRENT_SOURCE_DIR}/openvpn" "--tags" "--always" "--long")
|
||||
git_describe(OPENVPN3_GIT "${CMAKE_CURRENT_SOURCE_DIR}/openvpn3" "--tags" "--always" "--long")
|
||||
message("OpenVPN 2.x version ${OPENVPN2_GIT}")
|
||||
message("OpenVPN 3.x version ${OPENVPN3_GIT}")
|
||||
|
||||
# Set mbedtls options
|
||||
OPTION(ENABLE_PROGRAMS "" OFF)
|
||||
OPTION(USE_SHARED_MBEDTLS_LIBRARY "" OFF)
|
||||
OPTION(ENABLE_TESTING "" OFF)
|
||||
|
||||
# Own options
|
||||
OPTION(OPENVPN2MBED "Use mbed TLS for OpenVPN2" OFF)
|
||||
OPTION(OPENVPN3OSSL "Use OpenSSL for OpenVPN3" ON)
|
||||
SET(OPENVPN2MBED OFF)
|
||||
SET(OPENVPN3OSSL ON)
|
||||
|
||||
# STATIC or SHARED
|
||||
SET(SSLLIBTYPE STATIC)
|
||||
SET(OPENSSL_PATH "openssl")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
|
||||
#add_subdirectory(lzo)
|
||||
include(tools.cmake)
|
||||
include(lzo.cmake)
|
||||
include(lz4.cmake)
|
||||
include(openssl/openssl.cmake)
|
||||
include(cloak.cmake)
|
||||
|
||||
if(NOT ${OPENVPN3OSSL} OR ${OPENVPN2MBED})
|
||||
add_subdirectory(mbedtls)
|
||||
endif()
|
||||
|
||||
FIND_PACKAGE(SWIG 3.0 REQUIRED)
|
||||
|
||||
add_custom_command(OUTPUT "ovpncli_wrap.cxx"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ovpn3
|
||||
COMMAND ${SWIG_EXECUTABLE} -outdir ovpn3
|
||||
-c++
|
||||
-java -package net.openvpn.ovpn3
|
||||
-outcurrentdir
|
||||
-DOPENVPN_PLATFORM_ANDROID
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/openvpn3/client
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/openvpn3
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openvpn3/client/ovpncli.i)
|
||||
|
||||
|
||||
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/cloak/${ANDROID_ABI}/)
|
||||
|
||||
|
||||
message("${CMAKE_CURRENT_SOURCE_DIR}/cloak/${ANDROID_ABI}/"})
|
||||
|
||||
set(ovpn3_SRCS
|
||||
openvpn3/client/ovpncli.cpp
|
||||
openvpn3/openvpn/openssl/xkey/xkey_provider.c
|
||||
openvpn3/openvpn/openssl/xkey/xkey_helper.c
|
||||
ovpncli_wrap.cxx)
|
||||
|
||||
add_library(ovpn3 SHARED ${ovpn3_SRCS})
|
||||
|
||||
target_include_directories(ovpn3 PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lzo/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openvpn3
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/asio/asio/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openvpn3/client
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mbedtls/include
|
||||
)
|
||||
|
||||
if (${OPENVPN3OSSL})
|
||||
target_compile_definitions(ovpn3 PRIVATE
|
||||
-DUSE_OPENSSL
|
||||
)
|
||||
target_link_libraries(ovpn3 crypto ssl lzo lz4 libck-ovpn-plugin)
|
||||
else ()
|
||||
target_compile_definitions(ovpn3 PRIVATE
|
||||
-DUSE_MBEDTLS
|
||||
)
|
||||
target_link_libraries(ovpn3 mbedtls mbedx509 mbedcrypto lzo lz4)
|
||||
endif ()
|
||||
|
||||
target_compile_definitions(ovpn3 PRIVATE
|
||||
-DHAVE_CONFIG_H
|
||||
-DHAVE_LZO
|
||||
-DHAVE_LZ4
|
||||
-DASIO_STANDALONE
|
||||
-DUSE_ASIO
|
||||
-DGIT_VERSION_STRING=\"${OPENVPN3_GIT}\"
|
||||
-DOPENVPN_SHOW_SESSION_TOKEN
|
||||
-DOPENSSL_API_COMPAT=0x10200000L
|
||||
-DOPENVPN_ALLOW_INSECURE_CERTPROFILE
|
||||
-DENABLE_EXTERNAL_PKI
|
||||
)
|
||||
#else ()
|
||||
# message("Not budiling OpenVPN for output dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
|
||||
#endif ()
|
||||
|
||||
add_library(ovpnutil SHARED ovpnutil/jniglue.c)
|
||||
target_compile_definitions(ovpnutil PRIVATE -DTARGET_ARCH_ABI=\"${ANDROID_ABI}\"
|
||||
-DOPENVPN2_GIT_REVISION=\"${OPENVPN2_GIT}\"
|
||||
-DOPENVPN3_GIT_REVISION=\"${OPENVPN3_GIT}\"
|
||||
)
|
||||
target_link_libraries(ovpnutil log)
|
||||
|
||||
add_library(rsapss SHARED ovpnutil/rsapss.cpp)
|
||||
target_link_libraries(rsapss log crypto ssl)
|
||||
|
||||
if (NOT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} MATCHES "build/intermediates/cmake/.*skeleton.*/")
|
||||
add_library(osslspeedtest SHARED ovpnutil/sslspeed.c)
|
||||
target_link_libraries(osslspeedtest log crypto ssl)
|
||||
else ()
|
||||
message("Not budiling SSLSpeedTest for output dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
|
||||
endif ()
|
||||
|
||||
set(openvpn_srcs
|
||||
src/compat/compat-basename.c
|
||||
src/compat/compat-daemon.c
|
||||
src/compat/compat-dirname.c
|
||||
src/compat/compat-gettimeofday.c
|
||||
src/openvpn/argv.c
|
||||
src/openvpn/auth_token.c
|
||||
src/openvpn/base64.c
|
||||
src/openvpn/buffer.c
|
||||
src/openvpn/clinat.c
|
||||
src/openvpn/console.c
|
||||
src/openvpn/console_builtin.c
|
||||
src/openvpn/crypto.c
|
||||
src/openvpn/crypto_openssl.c
|
||||
src/openvpn/crypto_mbedtls.c
|
||||
src/openvpn/cryptoapi.c
|
||||
src/openvpn/dhcp.c
|
||||
src/openvpn/dns.c
|
||||
src/openvpn/dns.h
|
||||
src/openvpn/error.c
|
||||
src/openvpn/event.c
|
||||
src/openvpn/env_set.c
|
||||
src/openvpn/fdmisc.c
|
||||
src/openvpn/forward.c
|
||||
src/openvpn/fragment.c
|
||||
src/openvpn/gremlin.c
|
||||
src/openvpn/helper.c
|
||||
src/openvpn/httpdigest.c
|
||||
src/openvpn/init.c
|
||||
src/openvpn/interval.c
|
||||
src/openvpn/list.c
|
||||
src/openvpn/lladdr.c
|
||||
src/openvpn/lzo.c
|
||||
src/openvpn/manage.c
|
||||
src/openvpn/mbuf.c
|
||||
src/openvpn/misc.c
|
||||
src/openvpn/mroute.c
|
||||
src/openvpn/mss.c
|
||||
src/openvpn/mstats.c
|
||||
src/openvpn/mtcp.c
|
||||
src/openvpn/mtu.c
|
||||
src/openvpn/mudp.c
|
||||
src/openvpn/multi.c
|
||||
src/openvpn/ntlm.c
|
||||
src/openvpn/occ.c
|
||||
src/openvpn/openvpn.c
|
||||
src/openvpn/options.c
|
||||
src/openvpn/options_util.c
|
||||
src/openvpn/otime.c
|
||||
src/openvpn/packet_id.c
|
||||
src/openvpn/perf.c
|
||||
src/openvpn/ping.c
|
||||
src/openvpn/pkcs11.c
|
||||
src/openvpn/pkcs11_openssl.c
|
||||
src/openvpn/platform.c
|
||||
src/openvpn/plugin.c
|
||||
src/openvpn/pool.c
|
||||
src/openvpn/proto.c
|
||||
src/openvpn/proxy.c
|
||||
src/openvpn/ps.c
|
||||
src/openvpn/push.c
|
||||
src/openvpn/reliable.c
|
||||
src/openvpn/route.c
|
||||
src/openvpn/run_command.c
|
||||
src/openvpn/schedule.c
|
||||
src/openvpn/session_id.c
|
||||
src/openvpn/shaper.c
|
||||
src/openvpn/sig.c
|
||||
src/openvpn/socket.c
|
||||
src/openvpn/socks.c
|
||||
src/openvpn/ssl.c
|
||||
src/openvpn/ssl_openssl.c
|
||||
src/openvpn/ssl_mbedtls.c
|
||||
src/openvpn/ssl_ncp.c
|
||||
src/openvpn/ssl_pkt.c
|
||||
src/openvpn/ssl_pkt.h
|
||||
src/openvpn/ssl_util.c
|
||||
src/openvpn/ssl_verify.c
|
||||
src/openvpn/ssl_verify_openssl.c
|
||||
src/openvpn/ssl_verify_mbedtls.c
|
||||
src/openvpn/status.c
|
||||
src/openvpn/tls_crypt.c
|
||||
src/openvpn/tun.c
|
||||
src/openvpn/vlan.c
|
||||
src/openvpn/xkey_helper.c
|
||||
src/openvpn/xkey_provider.c
|
||||
src/openvpn/comp-lz4.c
|
||||
src/openvpn/comp.c
|
||||
src/openvpn/compstub.c
|
||||
)
|
||||
|
||||
PREPEND(openvpn_srcs_with_path "openvpn" ${openvpn_srcs})
|
||||
|
||||
add_library(openvpn SHARED ${openvpn_srcs_with_path})
|
||||
|
||||
target_include_directories(openvpn PRIVATE
|
||||
openvpn-config
|
||||
openvpn/src/compat
|
||||
openvpn/include
|
||||
mbedtls/include
|
||||
lzo/include
|
||||
openvpn
|
||||
)
|
||||
target_compile_definitions(openvpn PRIVATE
|
||||
-DHAVE_CONFIG_H
|
||||
-DCONFIGURE_GIT_REVISION=\"${OPENVPN2_GIT}\"
|
||||
-DCONFIGURE_GIT_FLAGS=\"\"
|
||||
-DTARGET_ABI=\"${ANDROID_ABI}\"
|
||||
-DOPENSSL_API_COMPAT=0x11000000L
|
||||
)
|
||||
|
||||
if (${OPENVPN2MBED})
|
||||
target_compile_definitions(openvpn PRIVATE
|
||||
-DENABLE_CRYPTO_MBEDTLS=1
|
||||
)
|
||||
target_link_libraries(openvpn mbedtls mbedx509 mbedcrypto lzo lz4)
|
||||
else ()
|
||||
target_compile_definitions(openvpn PRIVATE
|
||||
-DENABLE_CRYPTO_OPENSSL=1
|
||||
)
|
||||
target_link_libraries(openvpn crypto ssl lzo lz4)
|
||||
endif ()
|
||||
|
||||
add_executable(libovpnexec.so minivpn/minivpn.c)
|
||||
target_compile_options(libovpnexec.so PRIVATE -fPIE)
|
||||
target_link_libraries(libovpnexec.so PRIVATE openvpn -fPIE -pie)
|
||||
|
||||
add_executable(pie_openvpn.${ANDROID_ABI} minivpn/minivpn.c)
|
||||
target_compile_options(pie_openvpn.${ANDROID_ABI} PRIVATE -fPIE)
|
||||
target_link_libraries(pie_openvpn.${ANDROID_ABI} PRIVATE openvpn -fPIE -pie)
|
||||
|
||||
# Hack to copy OpenVPN binaries to assets directory
|
||||
SET(OVPN_ASSET_DIR ${CMAKE_SOURCE_DIR}/../../../build/ovpnassets)
|
||||
|
||||
add_custom_target(makeassetdir ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${OVPN_ASSET_DIR})
|
||||
|
||||
add_custom_command(TARGET pie_openvpn.${ANDROID_ABI} POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy
|
||||
$<TARGET_FILE:pie_openvpn.${ANDROID_ABI}>
|
||||
${OVPN_ASSET_DIR}
|
||||
)
|
||||
|
||||
# Hack that these targets are really executed
|
||||
add_dependencies(ovpnutil pie_openvpn.${ANDROID_ABI})
|
||||
add_dependencies(pie_openvpn.${ANDROID_ABI} makeassetdir)
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
# From https://raw.githubusercontent.com/rpavlik/cmake-modules/master/GetGitRevisionDescription.cmake.in
|
||||
# - Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the source tree, and adjusting
|
||||
# the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree,
|
||||
# and adjusting the output so that it tests false if there was no exact
|
||||
# matching tag.
|
||||
#
|
||||
# git_local_changes(<var>)
|
||||
#
|
||||
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||
# Does not regard untracked files.
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar path)
|
||||
set(GIT_PARENT_DIR "${path}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||
"${GIT_DATA}/grabRef.cmake"
|
||||
@ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var path)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash ${path})
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize
|
||||
#if((${ARGN}" MATCHES "&&") OR
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
#endif()
|
||||
|
||||
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
${path}
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var path)
|
||||
git_describe(out ${path} --exact-match ${ARGN})
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_local_changes _var path)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash path)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
diff-index --quiet HEAD --
|
||||
WORKING_DIRECTORY
|
||||
${path}
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(res EQUAL 0)
|
||||
set(${_var} "CLEAN" PARENT_SCOPE)
|
||||
else()
|
||||
set(${_var} "DIRTY" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,42 +0,0 @@
|
||||
# From https://raw.githubusercontent.com/rpavlik/cmake-modules/master/GetGitRevisionDescription.cmake.in
|
||||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
Submodule client/android/cpp/asio deleted from 4915cfd8a1
Submodule client/android/cpp/cloak deleted from 6d19a801bc
@@ -1,50 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(TARGET ck_ovpn_plugin_go)
|
||||
|
||||
set(CLOAK_SRCS cloak/cmd/ck-ovpn-plugin/ck-ovpn-plugin.go)
|
||||
set(CLOAK_LIB libck-ovpn-plugin.so)
|
||||
|
||||
list(APPEND CMAKE_PROGRAM_PATH "/usr/local/go/bin")
|
||||
find_program(GO_EXEC go)
|
||||
|
||||
set(BUILD_CMD_ARGS build)
|
||||
list(APPEND BUILD_CMD_ARGS -buildmode=c-shared -o ${CMAKE_CURRENT_BINARY_DIR}/${CLOAK_LIB} ${CMAKE_GO_FLAGS} ./...)
|
||||
|
||||
set(PREPARE_ENV_ARGS env)
|
||||
list(APPEND PREPARE_ENV_ARGS -w CGO_ENABLED=1 GOOS=android)
|
||||
|
||||
|
||||
string(REGEX MATCH "[0-9]+$" ANDROID_API_LEVEL ${ANDROID_PLATFORM})
|
||||
message(WARNING "build cloak plugin abi=${ANDROID_ABI}, ANDROID_API_LEVEL=${ANDROID_API_LEVEL}")
|
||||
|
||||
if ("${ANDROID_ABI}" STREQUAL "x86")
|
||||
list(APPEND PREPARE_ENV_ARGS GOARCH=386)
|
||||
list(APPEND PREPARE_ENV_ARGS CC=${ANDROID_TOOLCHAIN_ROOT}/bin/i686-linux-android${ANDROID_API_LEVEL}-clang)
|
||||
elseif ("${ANDROID_ABI}" STREQUAL "x86_64")
|
||||
list(APPEND PREPARE_ENV_ARGS GOARCH=amd64)
|
||||
list(APPEND PREPARE_ENV_ARGS CC=${ANDROID_TOOLCHAIN_ROOT}/bin/x86_64-linux-android${ANDROID_API_LEVEL}-clang)
|
||||
elseif ("${ANDROID_ABI}" STREQUAL "arm64-v8a")
|
||||
list(APPEND PREPARE_ENV_ARGS GOARCH=arm64)
|
||||
list(APPEND PREPARE_ENV_ARGS CC=${ANDROID_TOOLCHAIN_ROOT}/bin/aarch64-linux-android${ANDROID_API_LEVEL}-clang)
|
||||
elseif ("${ANDROID_ABI}" STREQUAL "armeabi-v7a")
|
||||
list(APPEND PREPARE_ENV_ARGS GOARCH=arm)
|
||||
list(APPEND PREPARE_ENV_ARGS GOARM=7)
|
||||
list(APPEND PREPARE_ENV_ARGS CC=${ANDROID_TOOLCHAIN_ROOT}/bin/armv7a-linux-androideabi${ANDROID_API_LEVEL}-clang)
|
||||
endif ()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CLOAK_LIB}
|
||||
DEPENDS ${CLOAK_SRCS}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cloak/cmd/ck-ovpn-plugin
|
||||
COMMAND ${GO_EXEC} ${PREPARE_ENV_ARGS}
|
||||
COMMAND ${GO_EXEC} ${BUILD_CMD_ARGS}
|
||||
COMMENT "Building Go library")
|
||||
|
||||
add_custom_target(${TARGET} DEPENDS ${CLOAK_LIB} ${HEADER})
|
||||
add_library(libck-ovpn-plugin STATIC IMPORTED GLOBAL)
|
||||
add_dependencies(libck-ovpn-plugin ${TARGET})
|
||||
set_target_properties(libck-ovpn-plugin
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${CLOAK_LIB}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})
|
||||
Submodule client/android/cpp/lz4 deleted from d44371841a
@@ -1,7 +0,0 @@
|
||||
set(lz4_srcs
|
||||
lz4.c
|
||||
)
|
||||
|
||||
PREPEND(lz4_src_with_path "lz4/lib/" ${lz4_srcs})
|
||||
add_library(lz4 ${lz4_src_with_path})
|
||||
target_include_directories(lz4 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/lz4/lib")
|
||||
Submodule client/android/cpp/lzo deleted from 5754571c89
@@ -1,78 +0,0 @@
|
||||
# Lzo's own cmake is rather throublesome
|
||||
|
||||
set(lzo_srcs
|
||||
lzo1.c
|
||||
lzo1_99.c
|
||||
lzo1a.c
|
||||
lzo1a_99.c
|
||||
lzo1b_1.c
|
||||
lzo1b_2.c
|
||||
lzo1b_3.c
|
||||
lzo1b_4.c
|
||||
lzo1b_5.c
|
||||
lzo1b_6.c
|
||||
lzo1b_7.c
|
||||
lzo1b_8.c
|
||||
lzo1b_9.c
|
||||
lzo1b_99.c
|
||||
lzo1b_9x.c
|
||||
lzo1b_cc.c
|
||||
lzo1b_d1.c
|
||||
lzo1b_d2.c
|
||||
lzo1b_rr.c
|
||||
lzo1b_xx.c
|
||||
lzo1c_1.c
|
||||
lzo1c_2.c
|
||||
lzo1c_3.c
|
||||
lzo1c_4.c
|
||||
lzo1c_5.c
|
||||
lzo1c_6.c
|
||||
lzo1c_7.c
|
||||
lzo1c_8.c
|
||||
lzo1c_9.c
|
||||
lzo1c_99.c
|
||||
lzo1c_9x.c
|
||||
lzo1c_cc.c
|
||||
lzo1c_d1.c
|
||||
lzo1c_d2.c
|
||||
lzo1c_rr.c
|
||||
lzo1c_xx.c
|
||||
lzo1f_1.c
|
||||
lzo1f_9x.c
|
||||
lzo1f_d1.c
|
||||
lzo1f_d2.c
|
||||
lzo1x_1.c
|
||||
lzo1x_1k.c
|
||||
lzo1x_1l.c
|
||||
lzo1x_1o.c
|
||||
lzo1x_9x.c
|
||||
lzo1x_d1.c
|
||||
lzo1x_d2.c
|
||||
lzo1x_d3.c
|
||||
lzo1x_o.c
|
||||
lzo1y_1.c
|
||||
lzo1y_9x.c
|
||||
lzo1y_d1.c
|
||||
lzo1y_d2.c
|
||||
lzo1y_d3.c
|
||||
lzo1y_o.c
|
||||
lzo1z_9x.c
|
||||
lzo1z_d1.c
|
||||
lzo1z_d2.c
|
||||
lzo1z_d3.c
|
||||
lzo2a_9x.c
|
||||
lzo2a_d1.c
|
||||
lzo2a_d2.c
|
||||
lzo_crc.c
|
||||
lzo_init.c
|
||||
lzo_ptr.c
|
||||
lzo_str.c
|
||||
lzo_util.c
|
||||
)
|
||||
|
||||
PREPEND(lzo_src_with_path "lzo/src" ${lzo_srcs})
|
||||
add_library(lzo ${lzo_src_with_path})
|
||||
target_include_directories(lzo PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/lzo/include")
|
||||
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
|
||||
target_compile_options(lzo PRIVATE -O0)
|
||||
endif()
|
||||
Submodule client/android/cpp/mbedtls deleted from b1c8e41ae3
Submodule client/android/cpp/openssl deleted from 5a6a7d0c95
Submodule client/android/cpp/openvpn deleted from b1ae59746c
@@ -1,684 +0,0 @@
|
||||
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
|
||||
/* DISABLE PERSISTEN TUN */
|
||||
#undef TUNSETPERSIST
|
||||
|
||||
/* Enable deferred authentication */
|
||||
#define CONFIGURE_DEF_AUTH 1
|
||||
|
||||
/* Enable internal packet filter */
|
||||
#undef CONFIGURE_PF //1
|
||||
|
||||
/* enable iproute2 support */
|
||||
#undef CONFIG_FEATURE_IPROUTE
|
||||
|
||||
/* Use memory debugging function in OpenSSL */
|
||||
/* #undef CRYPTO_MDEBUG */
|
||||
#define HAVE_BASENAME
|
||||
/* Use dmalloc memory debugging library */
|
||||
/* #undef DMALLOC */
|
||||
|
||||
/* Dimension to use for empty array declaration */
|
||||
#define EMPTY_ARRAY_SIZE 0
|
||||
|
||||
/* Enable client capability only */
|
||||
#define ENABLE_CLIENT_ONLY 1
|
||||
|
||||
/* Enable debugging support */
|
||||
#define ENABLE_DEBUG 1
|
||||
|
||||
/* Enable internal fragmentation support */
|
||||
#define ENABLE_FRAGMENT 1
|
||||
|
||||
/* Enable HTTP proxy support */
|
||||
#define ENABLE_HTTP_PROXY 1
|
||||
|
||||
/* Enable management server capability */
|
||||
#define ENABLE_MANAGEMENT 1
|
||||
|
||||
/* Enable multi-homed UDP server capability */
|
||||
#define ENABLE_MULTIHOME 0
|
||||
|
||||
/* Allow --askpass and --auth-user-pass passwords to be read from a file */
|
||||
#define ENABLE_PASSWORD_SAVE 1
|
||||
|
||||
/* Enable TCP Server port sharing */
|
||||
#define ENABLE_PORT_SHARE 1
|
||||
|
||||
/* Enable smaller executable size */
|
||||
/* #undef ENABLE_SMALL */
|
||||
|
||||
/* Enable Socks proxy support */
|
||||
#define ENABLE_SOCKS 1
|
||||
|
||||
/* Define to 1 if you have the `accept' function. */
|
||||
#define HAVE_ACCEPT 1
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
|
||||
/* Define to 1 if you have the `bind' function. */
|
||||
#define HAVE_BIND 1
|
||||
|
||||
/* Define to 1 if you have the `chdir' function. */
|
||||
#define HAVE_CHDIR 1
|
||||
|
||||
/* Define to 1 if you have the `chroot' function. */
|
||||
#define HAVE_CHROOT 1
|
||||
|
||||
/* Define to 1 if you have the `chsize' function. */
|
||||
/* #undef HAVE_CHSIZE */
|
||||
|
||||
/* struct cmsghdr needed for extended socket error support */
|
||||
#define HAVE_CMSGHDR 1
|
||||
|
||||
/* Define to 1 if you have the `connect' function. */
|
||||
#define HAVE_CONNECT 1
|
||||
|
||||
/* Define to 1 if your compiler supports GNU GCC-style variadic macros */
|
||||
#define HAVE_CPP_VARARG_MACRO_GCC 1
|
||||
|
||||
/* Define to 1 if your compiler supports ISO C99 variadic macros */
|
||||
#define HAVE_CPP_VARARG_MACRO_ISO 1
|
||||
|
||||
/* Define to 1 if you have the `ctime' function. */
|
||||
#define HAVE_CTIME 1
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#define HAVE_CTYPE_H 1
|
||||
|
||||
/* Define to 1 if you have the `daemon' function. */
|
||||
#define HAVE_DAEMON 1
|
||||
|
||||
/* Define to 1 if you have the `dup' function. */
|
||||
#define HAVE_DUP 1
|
||||
|
||||
/* Define to 1 if you have the `dup2' function. */
|
||||
#define HAVE_DUP2 1
|
||||
|
||||
/* Define to 1 if you have the `ENGINE_cleanup' function. */
|
||||
#define HAVE_ENGINE_CLEANUP 0
|
||||
|
||||
/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
|
||||
#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 0
|
||||
|
||||
/* Define to 1 if you have the `ENGINE_register_all_complete' function. */
|
||||
#define HAVE_ENGINE_REGISTER_ALL_COMPLETE 0
|
||||
|
||||
/* epoll_create function is defined */
|
||||
#define HAVE_EPOLL_CREATE 1
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#define HAVE_ERRNO_H 1
|
||||
|
||||
/* Define to 1 if you have the <err.h> header file. */
|
||||
#define HAVE_ERR_H 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_CIPHER_CTX_set_key_length' function. */
|
||||
#define HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH 1
|
||||
|
||||
/* Define to 1 if you have the `execve' function. */
|
||||
#define HAVE_EXECVE 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `flock' function. */
|
||||
#define HAVE_FLOCK 1
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#define HAVE_FORK 1
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#define HAVE_FTRUNCATE 1
|
||||
|
||||
/* Define to 1 if you have the `getgrnam' function. */
|
||||
#define HAVE_GETGRNAM 1
|
||||
|
||||
/* Define to 1 if you have the `gethostbyname' function. */
|
||||
#define HAVE_GETHOSTBYNAME 1
|
||||
|
||||
/* Define to 1 if you have the `getpass' function. */
|
||||
/* #define HAVE_GETPASS 1 */
|
||||
|
||||
/* Define to 1 if you have the `getpeereid' function. */
|
||||
/* #undef HAVE_GETPEEREID */
|
||||
|
||||
/* Define to 1 if you have the `getpeername' function. */
|
||||
#define HAVE_GETPEERNAME 1
|
||||
|
||||
/* Define to 1 if you have the `getpid' function. */
|
||||
#define HAVE_GETPID 1
|
||||
|
||||
/* Define to 1 if you have the `getpwnam' function. */
|
||||
#define HAVE_GETPWNAM 1
|
||||
|
||||
/* Define to 1 if you have the `getsockname' function. */
|
||||
#define HAVE_GETSOCKNAME 1
|
||||
|
||||
/* Define to 1 if you have the `getsockopt' function. */
|
||||
#define HAVE_GETSOCKOPT 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#define HAVE_GRP_H 1
|
||||
|
||||
/* Define to 1 if you have the `inet_ntoa' function. */
|
||||
#define HAVE_INET_NTOA 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* struct in_pktinfo needed for IP_PKTINFO support */
|
||||
#define HAVE_IN_PKTINFO 1
|
||||
|
||||
#define HAVE_IPI_SPEC_DST 1
|
||||
|
||||
/* struct iovec needed for IPv6 support */
|
||||
#define HAVE_IOVEC 1
|
||||
|
||||
/* struct iphdr needed for IPv6 support */
|
||||
#define HAVE_IPHDR 1
|
||||
|
||||
/* Define to 1 if you have the <linux/errqueue.h> header file. */
|
||||
#define HAVE_LINUX_ERRQUEUE_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/if_tun.h> header file. */
|
||||
#define HAVE_LINUX_IF_TUN_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/sockios.h> header file. */
|
||||
#define HAVE_LINUX_SOCKIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/types.h> header file. */
|
||||
#define HAVE_LINUX_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `listen' function. */
|
||||
#define HAVE_LISTEN 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the `mlockall' function. */
|
||||
/* #define HAVE_MLOCKALL 1*/
|
||||
|
||||
/* struct msghdr needed for extended socket error support */
|
||||
#define HAVE_MSGHDR 1
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#define HAVE_NETDB_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/if_ether.h> header file. */
|
||||
#define HAVE_NETINET_IF_ETHER_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in_systm.h> header file. */
|
||||
#define HAVE_NETINET_IN_SYSTM_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/ip.h> header file. */
|
||||
#define HAVE_NETINET_IP_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/tcp.h> header file. */
|
||||
#define HAVE_NETINET_TCP_H 1
|
||||
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#define HAVE_NET_IF_H 1
|
||||
|
||||
/* Define to 1 if you have the <net/if_tun.h> header file. */
|
||||
/* #undef HAVE_NET_IF_TUN_H */
|
||||
|
||||
/* Define to 1 if you have the <net/tun/if_tun.h> header file. */
|
||||
/* #undef HAVE_NET_TUN_IF_TUN_H */
|
||||
|
||||
/* Define to 1 if you have the `nice' function. */
|
||||
#define HAVE_NICE 1
|
||||
|
||||
/* Define to 1 if you have the `openlog' function. */
|
||||
#define HAVE_OPENLOG 1
|
||||
|
||||
/* Define to 1 if you have the <openssl/engine.h> header file. */
|
||||
#define HAVE_OPENSSL_ENGINE_H 0
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
#define HAVE_POLL 1
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
/* #undef HAVE_PTHREAD */
|
||||
|
||||
/* Define to 1 if you have the `putenv' function. */
|
||||
#define HAVE_PUTENV 1
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if you have the `readv' function. */
|
||||
#define HAVE_READV 1
|
||||
|
||||
/* Define to 1 if you have the `recv' function. */
|
||||
#define HAVE_RECV 1
|
||||
|
||||
/* Define to 1 if you have the `recvfrom' function. */
|
||||
#define HAVE_RECVFROM 1
|
||||
|
||||
/* Define to 1 if you have the `recvmsg' function. */
|
||||
#define HAVE_RECVMSG 1
|
||||
|
||||
/* Define to 1 if you have the <resolv.h> header file. */
|
||||
#define HAVE_RESOLV_H 1
|
||||
|
||||
/* Indicates if res_init is available */
|
||||
#define HAVE_RES_INIT 1
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have the `send' function. */
|
||||
#define HAVE_SEND 1
|
||||
|
||||
/* Define to 1 if you have the `sendmsg' function. */
|
||||
#define HAVE_SENDMSG 1
|
||||
|
||||
/* Define to 1 if you have the `sendto' function. */
|
||||
#define HAVE_SENDTO 1
|
||||
|
||||
/* SELinux support */
|
||||
/* #undef HAVE_SETCON */
|
||||
|
||||
/* Define to 1 if you have the `setgid' function. */
|
||||
#define HAVE_SETGID 1
|
||||
|
||||
/* Define to 1 if you have the `setgroups' function. */
|
||||
#define HAVE_SETGROUPS 1
|
||||
|
||||
/* Define to 1 if you have the `setsid' function. */
|
||||
#define HAVE_SETSID 1
|
||||
|
||||
/* Define to 1 if you have the `setsockopt' function. */
|
||||
#define HAVE_SETSOCKOPT 1
|
||||
|
||||
/* Define to 1 if you have the `setuid' function. */
|
||||
#define HAVE_SETUID 1
|
||||
|
||||
/* Define to 1 if you have the <signal.h> header file. */
|
||||
#define HAVE_SIGNAL_H 1
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#define HAVE_SOCKET 1
|
||||
|
||||
/* struct sock_extended_err needed for extended socket error support */
|
||||
#define HAVE_SOCK_EXTENDED_ERR 1
|
||||
|
||||
/* Define to 1 if you have the `stat' function. */
|
||||
#define HAVE_STAT 1
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#define HAVE_STDARG_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#define HAVE_STDIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <stropts.h> header file. */
|
||||
#define HAVE_STROPTS_H 1
|
||||
|
||||
/* Define to 1 if you have the `syslog' function. */
|
||||
#define HAVE_SYSLOG 1
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#define HAVE_SYSLOG_H 1
|
||||
|
||||
/* Define to 1 if you have the `system' function. */
|
||||
#define HAVE_SYSTEM 1
|
||||
|
||||
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
||||
#define HAVE_SYS_EPOLL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/file.h> header file. */
|
||||
#define HAVE_SYS_FILE_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
#define HAVE_POLL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define HAVE_SYS_SOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
/* #undef HAVE_SYS_SOCKIO_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#define HAVE_SYS_UIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/un.h> header file. */
|
||||
#define HAVE_SYS_UN_H 1
|
||||
|
||||
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
#define HAVE_SYS_WAIT_H 1
|
||||
|
||||
/* Define to 1 if you have the `time' function. */
|
||||
#define HAVE_TIME 1
|
||||
|
||||
/* struct tun_pi needed for IPv6 support */
|
||||
#define HAVE_TUN_PI 1
|
||||
|
||||
/* Define to 1 if you have the `umask' function. */
|
||||
#define HAVE_UMASK 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `unlink' function. */
|
||||
#define HAVE_UNLINK 1
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#define HAVE_VFORK 1
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
/* #undef HAVE_VFORK_H */
|
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */
|
||||
#define HAVE_VSNPRINTF 1
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#define HAVE_WORKING_FORK 1
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#define HAVE_WORKING_VFORK 1
|
||||
|
||||
/* Define to 1 if you have the `writev' function. */
|
||||
#define HAVE_WRITEV 1
|
||||
|
||||
/* Path to ifconfig tool */
|
||||
#define IFCONFIG_PATH "/system/xbin/ifconfig"
|
||||
|
||||
/* Path to iproute tool */
|
||||
#define IPROUTE_PATH "ip"
|
||||
|
||||
/* Use lzo/ directory prefix for LZO header files (for LZO 2.0) */
|
||||
#define LZO_HEADER_DIR 1
|
||||
|
||||
/* LZO version number */
|
||||
#define LZO_VERSION_NUM "2"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "openvpn"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "openvpn-users@lists.sourceforge.net"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "OpenVPN"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "OpenVPN 2.6-icsopenvpn"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "openvpn"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.6_master"
|
||||
|
||||
/* Define to the necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* Path to route tool */
|
||||
#define ROUTE_PATH "/system/xbin/route"
|
||||
|
||||
/* The size of `unsigned int', as computed by sizeof. */
|
||||
#define SIZEOF_UNSIGNED_INT 4
|
||||
|
||||
/* The size of `unsigned long', as computed by sizeof. */
|
||||
#define SIZEOF_UNSIGNED_LONG 4
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Enable strict options check between peers */
|
||||
/* #undef STRICT_OPTIONS_CHECK */
|
||||
|
||||
/* The TAP-Win32 id defined in tap-win32/SOURCES */
|
||||
#define TAP_ID "tap0901"
|
||||
|
||||
/* The TAP-Win32 version number is defined in tap-win32/SOURCES */
|
||||
#define TAP_WIN32_MIN_MAJOR 9
|
||||
|
||||
/* The TAP-Win32 version number is defined in tap-win32/SOURCES */
|
||||
#define TAP_WIN32_MIN_MINOR 1
|
||||
|
||||
/* A string representing our target */
|
||||
#define TARGET_ALIAS TARGET_ABI
|
||||
|
||||
/* Are we running on Mac OS X? */
|
||||
/* #undef TARGET_DARWIN */
|
||||
|
||||
/* Are we running on DragonFlyBSD? */
|
||||
/* #undef TARGET_DRAGONFLY */
|
||||
|
||||
/* Are we running on FreeBSD? */
|
||||
/* #undef TARGET_FREEBSD */
|
||||
|
||||
/* Are we running on Android Linux? */
|
||||
/* TARGET_LINUX is not enable since the TARGET_XXX options mainly
|
||||
control different tun/tap, ifconfig behaviour and Android VpnProvider
|
||||
is very different from Linux */
|
||||
#define TARGET_ANDROID
|
||||
|
||||
/* Are we running on Linux? */
|
||||
/* #define TARGET_LINUX 1 */
|
||||
|
||||
/* Are we running NetBSD? */
|
||||
/* #undef TARGET_NETBSD */
|
||||
|
||||
/* Are we running on OpenBSD? */
|
||||
/* #undef TARGET_OPENBSD */
|
||||
|
||||
/* Are we running on Solaris? */
|
||||
/* #undef TARGET_SOLARIS */
|
||||
|
||||
/* Are we running WIN32? */
|
||||
/* #undef TARGET_WIN32 */
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Win32 builtin */
|
||||
/* #undef UF */
|
||||
|
||||
/* Use OpenSSL crypto library */
|
||||
#define USE_CRYPTO 1
|
||||
|
||||
/* Use libdl for dynamic library loading */
|
||||
#define USE_LIBDL 1
|
||||
|
||||
/* Use LoadLibrary to load DLLs on Windows */
|
||||
/* #undef USE_LOAD_LIBRARY */
|
||||
|
||||
/* Use LZO compression library */
|
||||
#define ENABLE_LZO 1
|
||||
#define ENABLE_SNAPPY 1
|
||||
#define ENABLE_LZ4 1
|
||||
#define NEED_COMPAT_LZ4 1
|
||||
|
||||
/* Enable PKCS11 capability */
|
||||
/* #undef USE_PKCS11 */
|
||||
|
||||
/* Use pthread-based multithreading */
|
||||
/* #undef USE_PTHREAD */
|
||||
|
||||
/* Use OpenSSL SSL library */
|
||||
#define ENABLE_SSL 1
|
||||
#define USE_SSL 1
|
||||
#define ENABLE_CRYPTO 1
|
||||
|
||||
/* via android.mk */
|
||||
/*#define ENABLE_CRYPTO_OPENSSL 1*/
|
||||
/* #define ENABLE_CRYPTO_POLARSSL 1 */
|
||||
|
||||
/* Use valgrind memory debugging library */
|
||||
/* #undef USE_VALGRIND */
|
||||
|
||||
/* Version number of package */
|
||||
//#define VERSION "2.3.1"
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
/* #undef gid_t */
|
||||
|
||||
/* Some systems don't define in_addr_t */
|
||||
/* #undef in_addr_t */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef pid_t */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* type to use in place of socklen_t if not defined */
|
||||
/* #undef socklen_t */
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
/* #undef uid_t */
|
||||
|
||||
/* 16-bit unsigned type */
|
||||
/* #undef uint16_t */
|
||||
|
||||
/* 32-bit unsigned type */
|
||||
/* #undef uint32_t */
|
||||
|
||||
/* 8-bit unsigned type */
|
||||
/* #undef uint8_t */
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
/* #undef vfork */
|
||||
|
||||
/* Define to empty if the keyword `volatile' does not work. Warning: valid
|
||||
code using `volatile' can become incorrect without. Disable with care. */
|
||||
/* #undef volatile */
|
||||
|
||||
// New version
|
||||
#define HAVE_INET_NTOP 1
|
||||
#define HAVE_INET_PTON 1
|
||||
#define HAVE_LZO_LZOUTIL_H 1
|
||||
#define HAVE_LZO_LZO1X_H 1
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
#define HAVE_TIME_H 1
|
||||
// #define HAVE_CONFIG_VERSION_H 1
|
||||
#define PATH_SEPARATOR_STR "/"
|
||||
#define HAVE_SA_FAMILY_T 1
|
||||
|
||||
|
||||
// Workaround for bionc
|
||||
#define IPPROTO_IP IPPROTO_IP
|
||||
#define IPPROTO_TCP IPPROTO_TCP
|
||||
|
||||
int res_init();
|
||||
|
||||
#define HAVE_AEAD_CIPHER_MODES 1
|
||||
|
||||
#define HAVE_EVP_MD_CTX_RESET 1
|
||||
#define HAVE_EVP_MD_CTX_FREE 1
|
||||
#define HAVE_EVP_MD_CTX_NEW 1
|
||||
#define HAVE_EVP_CIPHER_CTX_FREE 1
|
||||
#define HAVE_EVP_CIPHER_CTX_NEW 1
|
||||
#define HAVE_HMAC_CTX_RESET 1
|
||||
#define HAVE_HMAC_CTX_FREE 1
|
||||
#define HAVE_HMAC_CTX_NEW 1
|
||||
#define HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA 1
|
||||
#define HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB 1
|
||||
#define HAVE_X509_GET0_PUBKEY 1
|
||||
#define HAVE_X509_STORE_GET0_OBJECTS 1
|
||||
#define HAVE_X509_OBJECT_FREE 1
|
||||
#define HAVE_X509_OBJECT_GET_TYPE 1
|
||||
#define HAVE_EVP_PKEY_GET0_RSA 1
|
||||
#define HAVE_EVP_PKEY_ID 1
|
||||
#define HAVE_EVP_PKEY_GET0_DSA 1
|
||||
#define HAVE_RSA_SET_FLAGS 1
|
||||
#define HAVE_RSA_GET0_KEY 1
|
||||
#define HAVE_RSA_SET0_KEY 1
|
||||
#define HAVE_RSA_BITS 1
|
||||
#define HAVE_DSA_BITS 1
|
||||
#define HAVE_DSA_GET0_PQG 1
|
||||
#define HAVE_RSA_METH_NEW 1
|
||||
#define HAVE_RSA_METH_FREE 1
|
||||
#define HAVE_RSA_METH_SET_PUB_ENC 1
|
||||
#define HAVE_RSA_METH_SET_PUB_DEC 1
|
||||
#define HAVE_RSA_METH_SET_PRIV_DEC 1
|
||||
#define HAVE_RSA_METH_SET_PRIV_ENC 1
|
||||
#define HAVE_RSA_METH_SET_INIT 1
|
||||
#define HAVE_RSA_METH_SET_FINISH 1
|
||||
#define HAVE_RSA_METH_SET0_APP_DATA 1
|
||||
#define HAVE_EVP_PKEY_GET0_EC_KEY 1
|
||||
#define HAVE_EC_GROUP_ORDER_BITS 1
|
||||
#define HAVE_RSA_METH_GET0_APP_DATA 1
|
||||
#define HAVE_RSA_METH_SET_SIGN 1
|
||||
|
||||
#define ENABLE_OFB_CFB_MODE 1
|
||||
|
||||
#define HAVE_X509_GET0_NOTBEFORE 1
|
||||
#define HAVE_X509_GET0_NOTAFTER 1
|
||||
|
||||
#define HAVE_OPENSSL_VERSION 1
|
||||
#define HAVE_EVP_CIPHER_CTX_RESET
|
||||
|
||||
|
||||
#define _SOCKLEN_T_DECLARED 1
|
||||
@@ -1,875 +0,0 @@
|
||||
/* include/openvpn-plugin.h. Generated from openvpn-plugin.h.in by configure. */
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef OPENVPN_PLUGIN_H_
|
||||
#define OPENVPN_PLUGIN_H_
|
||||
|
||||
#define OPENVPN_PLUGIN_VERSION 3
|
||||
|
||||
#ifdef ENABLE_CRYPTO_MBEDTLS
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#ifndef __OPENVPN_X509_CERT_T_DECLARED
|
||||
#define __OPENVPN_X509_CERT_T_DECLARED
|
||||
typedef mbedtls_x509_crt openvpn_x509_cert_t;
|
||||
#endif
|
||||
#else /* ifdef ENABLE_CRYPTO_MBEDTLS */
|
||||
#include <openssl/x509.h>
|
||||
#ifndef __OPENVPN_X509_CERT_T_DECLARED
|
||||
#define __OPENVPN_X509_CERT_T_DECLARED
|
||||
typedef X509 openvpn_x509_cert_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Provide some basic version information to plug-ins at OpenVPN compile time
|
||||
* This is will not be the complete version
|
||||
*/
|
||||
#define OPENVPN_VERSION_MAJOR 2
|
||||
#define OPENVPN_VERSION_MINOR 5
|
||||
#define OPENVPN_VERSION_PATCH "_git"
|
||||
|
||||
/*
|
||||
* Plug-in types. These types correspond to the set of script callbacks
|
||||
* supported by OpenVPN.
|
||||
*
|
||||
* This is the general call sequence to expect when running in server mode:
|
||||
*
|
||||
* Initial Server Startup:
|
||||
*
|
||||
* FUNC: openvpn_plugin_open_v1
|
||||
* FUNC: openvpn_plugin_client_constructor_v1 (this is the top-level "generic"
|
||||
* client template)
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_UP
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_ROUTE_UP
|
||||
*
|
||||
* New Client Connection:
|
||||
*
|
||||
* FUNC: openvpn_plugin_client_constructor_v1
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_ENABLE_PF
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
|
||||
* in the server chain)
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_IPCHANGE
|
||||
*
|
||||
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
|
||||
* we don't proceed until authentication is verified via auth_control_file]
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_CONNECT_V2
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_LEARN_ADDRESS
|
||||
*
|
||||
* [Client session ensues]
|
||||
*
|
||||
* For each "TLS soft reset", according to reneg-sec option (or similar):
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_ENABLE_PF
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
|
||||
* in the server chain)
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
|
||||
*
|
||||
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
|
||||
* we expect that authentication is verified via auth_control_file within
|
||||
* the number of seconds defined by the "hand-window" option. Data channel traffic
|
||||
* will continue to flow uninterrupted during this period.]
|
||||
*
|
||||
* [Client session continues]
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_DISCONNECT
|
||||
* FUNC: openvpn_plugin_client_destructor_v1
|
||||
*
|
||||
* [ some time may pass ]
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_LEARN_ADDRESS (this coincides with a
|
||||
* lazy free of initial
|
||||
* learned addr object)
|
||||
* Server Shutdown:
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_DOWN
|
||||
* FUNC: openvpn_plugin_client_destructor_v1 (top-level "generic" client)
|
||||
* FUNC: openvpn_plugin_close_v1
|
||||
*/
|
||||
#define OPENVPN_PLUGIN_UP 0
|
||||
#define OPENVPN_PLUGIN_DOWN 1
|
||||
#define OPENVPN_PLUGIN_ROUTE_UP 2
|
||||
#define OPENVPN_PLUGIN_IPCHANGE 3
|
||||
#define OPENVPN_PLUGIN_TLS_VERIFY 4
|
||||
#define OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY 5
|
||||
#define OPENVPN_PLUGIN_CLIENT_CONNECT 6
|
||||
#define OPENVPN_PLUGIN_CLIENT_DISCONNECT 7
|
||||
#define OPENVPN_PLUGIN_LEARN_ADDRESS 8
|
||||
#define OPENVPN_PLUGIN_CLIENT_CONNECT_V2 9
|
||||
#define OPENVPN_PLUGIN_TLS_FINAL 10
|
||||
#define OPENVPN_PLUGIN_ENABLE_PF 11
|
||||
#define OPENVPN_PLUGIN_ROUTE_PREDOWN 12
|
||||
#define OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER 13
|
||||
#define OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2 14
|
||||
#define OPENVPN_PLUGIN_CLIENT_CRRESPONSE 15
|
||||
#define OPENVPN_PLUGIN_N 16
|
||||
|
||||
/*
|
||||
* Build a mask out of a set of plug-in types.
|
||||
*/
|
||||
#define OPENVPN_PLUGIN_MASK(x) (1<<(x))
|
||||
|
||||
/*
|
||||
* A pointer to a plugin-defined object which contains
|
||||
* the object state.
|
||||
*/
|
||||
typedef void *openvpn_plugin_handle_t;
|
||||
|
||||
/*
|
||||
* Return value for openvpn_plugin_func_v1 function
|
||||
*/
|
||||
#define OPENVPN_PLUGIN_FUNC_SUCCESS 0
|
||||
#define OPENVPN_PLUGIN_FUNC_ERROR 1
|
||||
#define OPENVPN_PLUGIN_FUNC_DEFERRED 2
|
||||
|
||||
/*
|
||||
* For Windows (needs to be modified for MSVC)
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(OPENVPN_PLUGIN_H)
|
||||
#define OPENVPN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define OPENVPN_EXPORT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If OPENVPN_PLUGIN_H is defined, we know that we are being
|
||||
* included in an OpenVPN compile, rather than a plugin compile.
|
||||
*/
|
||||
#ifdef OPENVPN_PLUGIN_H
|
||||
|
||||
/*
|
||||
* We are compiling OpenVPN.
|
||||
*/
|
||||
#define OPENVPN_PLUGIN_DEF typedef
|
||||
#define OPENVPN_PLUGIN_FUNC(name) (*name)
|
||||
|
||||
#else /* ifdef OPENVPN_PLUGIN_H */
|
||||
|
||||
/*
|
||||
* We are compiling plugin.
|
||||
*/
|
||||
#define OPENVPN_PLUGIN_DEF OPENVPN_EXPORT
|
||||
#define OPENVPN_PLUGIN_FUNC(name) name
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used by openvpn_plugin_func to return structured
|
||||
* data. The plugin should allocate all structure
|
||||
* instances, name strings, and value strings with
|
||||
* malloc, since OpenVPN will assume that it
|
||||
* can free the list by calling free() over the same.
|
||||
*/
|
||||
struct openvpn_plugin_string_list
|
||||
{
|
||||
struct openvpn_plugin_string_list *next;
|
||||
char *name;
|
||||
char *value;
|
||||
};
|
||||
|
||||
|
||||
/* openvpn_plugin_{open,func}_v3() related structs */
|
||||
|
||||
/**
|
||||
* Defines version of the v3 plugin argument structs
|
||||
*
|
||||
* Whenever one or more of these structs are modified, this constant
|
||||
* must be updated. A changelog should be appended in this comment
|
||||
* as well, to make it easier to see what information is available
|
||||
* in the different versions.
|
||||
*
|
||||
* Version Comment
|
||||
* 1 Initial plugin v3 structures providing the same API as
|
||||
* the v2 plugin interface, X509 certificate information +
|
||||
* a logging API for plug-ins.
|
||||
*
|
||||
* 2 Added ssl_api member in struct openvpn_plugin_args_open_in
|
||||
* which identifies the SSL implementation OpenVPN is compiled
|
||||
* against.
|
||||
*
|
||||
* 3 Added ovpn_version, ovpn_version_major, ovpn_version_minor
|
||||
* and ovpn_version_patch to provide the runtime version of
|
||||
* OpenVPN to plug-ins.
|
||||
*
|
||||
* 4 Exported secure_memzero() as plugin_secure_memzero()
|
||||
*
|
||||
* 5 Exported openvpn_base64_encode() as plugin_base64_encode()
|
||||
* Exported openvpn_base64_decode() as plugin_base64_decode()
|
||||
*/
|
||||
#define OPENVPN_PLUGINv3_STRUCTVER 5
|
||||
|
||||
/**
|
||||
* Definitions needed for the plug-in callback functions.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
PLOG_ERR = (1 << 0),/* Error condition message */
|
||||
PLOG_WARN = (1 << 1),/* General warning message */
|
||||
PLOG_NOTE = (1 << 2),/* Informational message */
|
||||
PLOG_DEBUG = (1 << 3),/* Debug message, displayed if verb >= 7 */
|
||||
|
||||
PLOG_ERRNO = (1 << 8),/* Add error description to message */
|
||||
PLOG_NOMUTE = (1 << 9), /* Mute setting does not apply for message */
|
||||
|
||||
} openvpn_plugin_log_flags_t;
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if __USE_MINGW_ANSI_STDIO
|
||||
#define _ovpn_chk_fmt(a, b) __attribute__ ((format(gnu_printf, (a), (b))))
|
||||
#else
|
||||
#define _ovpn_chk_fmt(a, b) __attribute__ ((format(__printf__, (a), (b))))
|
||||
#endif
|
||||
#else /* ifdef __GNUC__ */
|
||||
#define _ovpn_chk_fmt(a, b)
|
||||
#endif
|
||||
|
||||
typedef void (*plugin_log_t)(openvpn_plugin_log_flags_t flags,
|
||||
const char *plugin_name,
|
||||
const char *format, ...) _ovpn_chk_fmt (3, 4);
|
||||
|
||||
typedef void (*plugin_vlog_t)(openvpn_plugin_log_flags_t flags,
|
||||
const char *plugin_name,
|
||||
const char *format,
|
||||
va_list arglist) _ovpn_chk_fmt (3, 0);
|
||||
/* #undef _ovpn_chk_fmt */
|
||||
|
||||
/**
|
||||
* Export of secure_memzero() to be used inside plug-ins
|
||||
*
|
||||
* @param data Pointer to data to zeroise
|
||||
* @param len Length of data, in bytes
|
||||
*
|
||||
*/
|
||||
typedef void (*plugin_secure_memzero_t)(void *data, size_t len);
|
||||
|
||||
/**
|
||||
* Export of openvpn_base64_encode() to be used inside plug-ins
|
||||
*
|
||||
* @param data Pointer to data to BASE64 encode
|
||||
* @param size Length of data, in bytes
|
||||
* @param *str Pointer to the return buffer. This needed memory is
|
||||
* allocated by openvpn_base64_encode() and needs to be free()d
|
||||
* after use.
|
||||
*
|
||||
* @return int Returns the length of the buffer created, or -1 on error.
|
||||
*
|
||||
*/
|
||||
typedef int (*plugin_base64_encode_t)(const void *data, int size, char **str);
|
||||
|
||||
/**
|
||||
* Export of openvpn_base64_decode() to be used inside plug-ins
|
||||
*
|
||||
* @param str Pointer to the BASE64 encoded data
|
||||
* @param data Pointer to the buffer where save the decoded data
|
||||
* @param size Size of the destination buffer
|
||||
*
|
||||
* @return int Returns the length of the decoded data, or -1 on error or
|
||||
* if the destination buffer is too small.
|
||||
*
|
||||
*/
|
||||
typedef int (*plugin_base64_decode_t)(const char *str, void *data, int size);
|
||||
|
||||
|
||||
/**
|
||||
* Used by the openvpn_plugin_open_v3() function to pass callback
|
||||
* function pointers to the plug-in.
|
||||
*
|
||||
* plugin_log
|
||||
* plugin_vlog : Use these functions to add information to the OpenVPN log file.
|
||||
* Messages will only be displayed if the plugin_name parameter
|
||||
* is set. PLOG_DEBUG messages will only be displayed with plug-in
|
||||
* debug log verbosity (at the time of writing that's verb >= 7).
|
||||
*
|
||||
* plugin_secure_memzero
|
||||
* : Use this function to securely wipe sensitive information from
|
||||
* memory. This function is declared in a way that the compiler
|
||||
* will not remove these function calls during the compiler
|
||||
* optimization phase.
|
||||
*/
|
||||
struct openvpn_plugin_callbacks
|
||||
{
|
||||
plugin_log_t plugin_log;
|
||||
plugin_vlog_t plugin_vlog;
|
||||
plugin_secure_memzero_t plugin_secure_memzero;
|
||||
plugin_base64_encode_t plugin_base64_encode;
|
||||
plugin_base64_decode_t plugin_base64_decode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the openvpn_plugin_open_v3() function to indicate to the
|
||||
* plug-in what kind of SSL implementation OpenVPN uses. This is
|
||||
* to avoid SEGV issues when OpenVPN is complied against mbed TLS
|
||||
* and the plug-in against OpenSSL.
|
||||
*/
|
||||
typedef enum {
|
||||
SSLAPI_NONE,
|
||||
SSLAPI_OPENSSL,
|
||||
SSLAPI_MBEDTLS
|
||||
} ovpnSSLAPI;
|
||||
|
||||
/**
|
||||
* Arguments used to transport variables to the plug-in.
|
||||
* The struct openvpn_plugin_args_open_in is only used
|
||||
* by the openvpn_plugin_open_v3() function.
|
||||
*
|
||||
* STRUCT MEMBERS
|
||||
*
|
||||
* type_mask : Set by OpenVPN to the logical OR of all script
|
||||
* types which this version of OpenVPN supports.
|
||||
*
|
||||
* argv : a NULL-terminated array of options provided to the OpenVPN
|
||||
* "plug-in" directive. argv[0] is the dynamic library pathname.
|
||||
*
|
||||
* envp : a NULL-terminated array of OpenVPN-set environmental
|
||||
* variables in "name=value" format. Note that for security reasons,
|
||||
* these variables are not actually written to the "official"
|
||||
* environmental variable store of the process.
|
||||
*
|
||||
* callbacks : a pointer to the plug-in callback function struct.
|
||||
*
|
||||
*/
|
||||
struct openvpn_plugin_args_open_in
|
||||
{
|
||||
const int type_mask;
|
||||
const char **const argv;
|
||||
const char **const envp;
|
||||
struct openvpn_plugin_callbacks *callbacks;
|
||||
const ovpnSSLAPI ssl_api;
|
||||
const char *ovpn_version;
|
||||
const unsigned int ovpn_version_major;
|
||||
const unsigned int ovpn_version_minor;
|
||||
const char *const ovpn_version_patch;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Arguments used to transport variables from the plug-in back
|
||||
* to the OpenVPN process. The struct openvpn_plugin_args_open_return
|
||||
* is only used by the openvpn_plugin_open_v3() function.
|
||||
*
|
||||
* STRUCT MEMBERS
|
||||
*
|
||||
* type_mask : The plug-in should set this value to the logical OR of all script
|
||||
* types which the plug-in wants to intercept. For example, if the
|
||||
* script wants to intercept the client-connect and client-disconnect
|
||||
* script types:
|
||||
*
|
||||
* type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT)
|
||||
* | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
|
||||
*
|
||||
* handle : Pointer to a global plug-in context, created by the plug-in. This pointer
|
||||
* is passed on to the other plug-in calls.
|
||||
*
|
||||
* return_list : used to return data back to OpenVPN.
|
||||
*
|
||||
*/
|
||||
struct openvpn_plugin_args_open_return
|
||||
{
|
||||
int type_mask;
|
||||
openvpn_plugin_handle_t handle;
|
||||
struct openvpn_plugin_string_list **return_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* Arguments used to transport variables to and from the
|
||||
* plug-in. The struct openvpn_plugin_args_func is only used
|
||||
* by the openvpn_plugin_func_v3() function.
|
||||
*
|
||||
* STRUCT MEMBERS:
|
||||
*
|
||||
* type : one of the PLUGIN_x types.
|
||||
*
|
||||
* argv : a NULL-terminated array of "command line" options which
|
||||
* would normally be passed to the script. argv[0] is the dynamic
|
||||
* library pathname.
|
||||
*
|
||||
* envp : a NULL-terminated array of OpenVPN-set environmental
|
||||
* variables in "name=value" format. Note that for security reasons,
|
||||
* these variables are not actually written to the "official"
|
||||
* environmental variable store of the process.
|
||||
*
|
||||
* handle : Pointer to a global plug-in context, created by the plug-in's openvpn_plugin_open_v3().
|
||||
*
|
||||
* per_client_context : the per-client context pointer which was returned by
|
||||
* openvpn_plugin_client_constructor_v1, if defined.
|
||||
*
|
||||
* current_cert_depth : Certificate depth of the certificate being passed over
|
||||
*
|
||||
* *current_cert : X509 Certificate object received from the client
|
||||
*
|
||||
*/
|
||||
struct openvpn_plugin_args_func_in
|
||||
{
|
||||
const int type;
|
||||
const char **const argv;
|
||||
const char **const envp;
|
||||
openvpn_plugin_handle_t handle;
|
||||
void *per_client_context;
|
||||
int current_cert_depth;
|
||||
openvpn_x509_cert_t *current_cert;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Arguments used to transport variables to and from the
|
||||
* plug-in. The struct openvpn_plugin_args_func is only used
|
||||
* by the openvpn_plugin_func_v3() function.
|
||||
*
|
||||
* STRUCT MEMBERS:
|
||||
*
|
||||
* return_list : used to return data back to OpenVPN for further processing/usage by
|
||||
* the OpenVPN executable.
|
||||
*
|
||||
*/
|
||||
struct openvpn_plugin_args_func_return
|
||||
{
|
||||
struct openvpn_plugin_string_list **return_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Multiple plugin modules can be cascaded, and modules can be
|
||||
* used in tandem with scripts. The order of operation is that
|
||||
* the module func() functions are called in the order that
|
||||
* the modules were specified in the config file. If a script
|
||||
* was specified as well, it will be called last. If the
|
||||
* return code of the module/script controls an authentication
|
||||
* function (such as tls-verify or auth-user-pass-verify), then
|
||||
* every module and script must return success (0) in order for
|
||||
* the connection to be authenticated.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Plugins which use a privilege-separation model (by forking in
|
||||
* their initialization function before the main OpenVPN process
|
||||
* downgrades root privileges and/or executes a chroot) must
|
||||
* daemonize after a fork if the "daemon" environmental variable is
|
||||
* set. In addition, if the "daemon_log_redirect" variable is set,
|
||||
* the plugin should preserve stdout/stderr across the daemon()
|
||||
* syscall. See the daemonize() function in plugin/auth-pam/auth-pam.c
|
||||
* for an example.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Prototypes for functions which OpenVPN plug-ins must define.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_open_v2
|
||||
*
|
||||
* REQUIRED: YES
|
||||
*
|
||||
* Called on initial plug-in load. OpenVPN will preserve plug-in state
|
||||
* across SIGUSR1 restarts but not across SIGHUP restarts. A SIGHUP reset
|
||||
* will cause the plugin to be closed and reopened.
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* *type_mask : Set by OpenVPN to the logical OR of all script
|
||||
* types which this version of OpenVPN supports. The plug-in
|
||||
* should set this value to the logical OR of all script types
|
||||
* which the plug-in wants to intercept. For example, if the
|
||||
* script wants to intercept the client-connect and
|
||||
* client-disconnect script types:
|
||||
*
|
||||
* *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT)
|
||||
* | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
|
||||
*
|
||||
* argv : a NULL-terminated array of options provided to the OpenVPN
|
||||
* "plug-in" directive. argv[0] is the dynamic library pathname.
|
||||
*
|
||||
* envp : a NULL-terminated array of OpenVPN-set environmental
|
||||
* variables in "name=value" format. Note that for security reasons,
|
||||
* these variables are not actually written to the "official"
|
||||
* environmental variable store of the process.
|
||||
*
|
||||
* return_list : used to return data back to OpenVPN.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* An openvpn_plugin_handle_t value on success, NULL on failure
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2)
|
||||
(unsigned int *type_mask,
|
||||
const char *argv[],
|
||||
const char *envp[],
|
||||
struct openvpn_plugin_string_list **return_list);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_func_v2
|
||||
*
|
||||
* Called to perform the work of a given script type.
|
||||
*
|
||||
* REQUIRED: YES
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* handle : the openvpn_plugin_handle_t value which was returned by
|
||||
* openvpn_plugin_open.
|
||||
*
|
||||
* type : one of the PLUGIN_x types
|
||||
*
|
||||
* argv : a NULL-terminated array of "command line" options which
|
||||
* would normally be passed to the script. argv[0] is the dynamic
|
||||
* library pathname.
|
||||
*
|
||||
* envp : a NULL-terminated array of OpenVPN-set environmental
|
||||
* variables in "name=value" format. Note that for security reasons,
|
||||
* these variables are not actually written to the "official"
|
||||
* environmental variable store of the process.
|
||||
*
|
||||
* per_client_context : the per-client context pointer which was returned by
|
||||
* openvpn_plugin_client_constructor_v1, if defined.
|
||||
*
|
||||
* return_list : used to return data back to OpenVPN.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
|
||||
*
|
||||
* In addition, OPENVPN_PLUGIN_FUNC_DEFERRED may be returned by
|
||||
* OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY. This enables asynchronous
|
||||
* authentication where the plugin (or one of its agents) may indicate
|
||||
* authentication success/failure some number of seconds after the return
|
||||
* of the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY handler by writing a single
|
||||
* char to the file named by auth_control_file in the environmental variable
|
||||
* list (envp).
|
||||
*
|
||||
* first char of auth_control_file:
|
||||
* '0' -- indicates auth failure
|
||||
* '1' -- indicates auth success
|
||||
*
|
||||
* OpenVPN will delete the auth_control_file after it goes out of scope.
|
||||
*
|
||||
* If an OPENVPN_PLUGIN_ENABLE_PF handler is defined and returns success
|
||||
* for a particular client instance, packet filtering will be enabled for that
|
||||
* instance. OpenVPN will then attempt to read the packet filter configuration
|
||||
* from the temporary file named by the environmental variable pf_file. This
|
||||
* file may be generated asynchronously and may be dynamically updated during the
|
||||
* client session, however the client will be blocked from sending or receiving
|
||||
* VPN tunnel packets until the packet filter file has been generated. OpenVPN
|
||||
* will periodically test the packet filter file over the life of the client
|
||||
* instance and reload when modified. OpenVPN will delete the packet filter file
|
||||
* when the client instance goes out of scope.
|
||||
*
|
||||
* Packet filter file grammar:
|
||||
*
|
||||
* [CLIENTS DROP|ACCEPT]
|
||||
* {+|-}common_name1
|
||||
* {+|-}common_name2
|
||||
* . . .
|
||||
* [SUBNETS DROP|ACCEPT]
|
||||
* {+|-}subnet1
|
||||
* {+|-}subnet2
|
||||
* . . .
|
||||
* [END]
|
||||
*
|
||||
* Subnet: IP-ADDRESS | IP-ADDRESS/NUM_NETWORK_BITS
|
||||
*
|
||||
* CLIENTS refers to the set of clients (by their common-name) which
|
||||
* this instance is allowed ('+') to connect to, or is excluded ('-')
|
||||
* from connecting to. Note that in the case of client-to-client
|
||||
* connections, such communication must be allowed by the packet filter
|
||||
* configuration files of both clients.
|
||||
*
|
||||
* SUBNETS refers to IP addresses or IP address subnets which this
|
||||
* instance may connect to ('+') or is excluded ('-') from connecting
|
||||
* to.
|
||||
*
|
||||
* DROP or ACCEPT defines default policy when there is no explicit match
|
||||
* for a common-name or subnet. The [END] tag must exist. A special
|
||||
* purpose tag called [KILL] will immediately kill the client instance.
|
||||
* A given client or subnet rule applies to both incoming and outgoing
|
||||
* packets.
|
||||
*
|
||||
* See plugin/defer/simple.c for an example on using asynchronous
|
||||
* authentication and client-specific packet filtering.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
|
||||
(openvpn_plugin_handle_t handle,
|
||||
const int type,
|
||||
const char *argv[],
|
||||
const char *envp[],
|
||||
void *per_client_context,
|
||||
struct openvpn_plugin_string_list **return_list);
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_open_v3
|
||||
*
|
||||
* REQUIRED: YES
|
||||
*
|
||||
* Called on initial plug-in load. OpenVPN will preserve plug-in state
|
||||
* across SIGUSR1 restarts but not across SIGHUP restarts. A SIGHUP reset
|
||||
* will cause the plugin to be closed and reopened.
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* version : fixed value, defines the API version of the OpenVPN plug-in API. The plug-in
|
||||
* should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER
|
||||
* value.
|
||||
*
|
||||
* arguments : Structure with all arguments available to the plug-in.
|
||||
*
|
||||
* retptr : used to return data back to OpenVPN.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v3)
|
||||
(const int version,
|
||||
struct openvpn_plugin_args_open_in const *arguments,
|
||||
struct openvpn_plugin_args_open_return *retptr);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_func_v3
|
||||
*
|
||||
* Called to perform the work of a given script type.
|
||||
*
|
||||
* REQUIRED: YES
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* version : fixed value, defines the API version of the OpenVPN plug-in API. The plug-in
|
||||
* should validate that this value is matching the OPENVPN_PLUGIN_VERSION value.
|
||||
*
|
||||
* handle : the openvpn_plugin_handle_t value which was returned by
|
||||
* openvpn_plugin_open.
|
||||
*
|
||||
* return_list : used to return data back to OpenVPN.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
|
||||
*
|
||||
* In addition, OPENVPN_PLUGIN_FUNC_DEFERRED may be returned by
|
||||
* OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY. This enables asynchronous
|
||||
* authentication where the plugin (or one of its agents) may indicate
|
||||
* authentication success/failure some number of seconds after the return
|
||||
* of the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY handler by writing a single
|
||||
* char to the file named by auth_control_file in the environmental variable
|
||||
* list (envp).
|
||||
*
|
||||
* first char of auth_control_file:
|
||||
* '0' -- indicates auth failure
|
||||
* '1' -- indicates auth success
|
||||
*
|
||||
* OpenVPN will delete the auth_control_file after it goes out of scope.
|
||||
*
|
||||
* If an OPENVPN_PLUGIN_ENABLE_PF handler is defined and returns success
|
||||
* for a particular client instance, packet filtering will be enabled for that
|
||||
* instance. OpenVPN will then attempt to read the packet filter configuration
|
||||
* from the temporary file named by the environmental variable pf_file. This
|
||||
* file may be generated asynchronously and may be dynamically updated during the
|
||||
* client session, however the client will be blocked from sending or receiving
|
||||
* VPN tunnel packets until the packet filter file has been generated. OpenVPN
|
||||
* will periodically test the packet filter file over the life of the client
|
||||
* instance and reload when modified. OpenVPN will delete the packet filter file
|
||||
* when the client instance goes out of scope.
|
||||
*
|
||||
* Packet filter file grammar:
|
||||
*
|
||||
* [CLIENTS DROP|ACCEPT]
|
||||
* {+|-}common_name1
|
||||
* {+|-}common_name2
|
||||
* . . .
|
||||
* [SUBNETS DROP|ACCEPT]
|
||||
* {+|-}subnet1
|
||||
* {+|-}subnet2
|
||||
* . . .
|
||||
* [END]
|
||||
*
|
||||
* Subnet: IP-ADDRESS | IP-ADDRESS/NUM_NETWORK_BITS
|
||||
*
|
||||
* CLIENTS refers to the set of clients (by their common-name) which
|
||||
* this instance is allowed ('+') to connect to, or is excluded ('-')
|
||||
* from connecting to. Note that in the case of client-to-client
|
||||
* connections, such communication must be allowed by the packet filter
|
||||
* configuration files of both clients.
|
||||
*
|
||||
* SUBNETS refers to IP addresses or IP address subnets which this
|
||||
* instance may connect to ('+') or is excluded ('-') from connecting
|
||||
* to.
|
||||
*
|
||||
* DROP or ACCEPT defines default policy when there is no explicit match
|
||||
* for a common-name or subnet. The [END] tag must exist. A special
|
||||
* purpose tag called [KILL] will immediately kill the client instance.
|
||||
* A given client or subnet rule applies to both incoming and outgoing
|
||||
* packets.
|
||||
*
|
||||
* See plugin/defer/simple.c for an example on using asynchronous
|
||||
* authentication and client-specific packet filtering.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v3)
|
||||
(const int version,
|
||||
struct openvpn_plugin_args_func_in const *arguments,
|
||||
struct openvpn_plugin_args_func_return *retptr);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_close_v1
|
||||
*
|
||||
* REQUIRED: YES
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* handle : the openvpn_plugin_handle_t value which was returned by
|
||||
* openvpn_plugin_open.
|
||||
*
|
||||
* Called immediately prior to plug-in unload.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1)
|
||||
(openvpn_plugin_handle_t handle);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_abort_v1
|
||||
*
|
||||
* REQUIRED: NO
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* handle : the openvpn_plugin_handle_t value which was returned by
|
||||
* openvpn_plugin_open.
|
||||
*
|
||||
* Called when OpenVPN is in the process of aborting due to a fatal error.
|
||||
* Will only be called on an open context returned by a prior successful
|
||||
* openvpn_plugin_open callback.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1)
|
||||
(openvpn_plugin_handle_t handle);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_client_constructor_v1
|
||||
*
|
||||
* Called to allocate a per-client memory region, which
|
||||
* is then passed to the openvpn_plugin_func_v2 function.
|
||||
* This function is called every time the OpenVPN server
|
||||
* constructs a client instance object, which normally
|
||||
* occurs when a session-initiating packet is received
|
||||
* by a new client, even before the client has authenticated.
|
||||
*
|
||||
* This function should allocate the private memory needed
|
||||
* by the plugin to track individual OpenVPN clients, and
|
||||
* return a void * to this memory region.
|
||||
*
|
||||
* REQUIRED: NO
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* handle : the openvpn_plugin_handle_t value which was returned by
|
||||
* openvpn_plugin_open.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* void * pointer to plugin's private per-client memory region, or NULL
|
||||
* if no memory region is required.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF void *OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_v1)
|
||||
(openvpn_plugin_handle_t handle);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_client_destructor_v1
|
||||
*
|
||||
* This function is called on client instance object destruction.
|
||||
*
|
||||
* REQUIRED: NO
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* handle : the openvpn_plugin_handle_t value which was returned by
|
||||
* openvpn_plugin_open.
|
||||
*
|
||||
* per_client_context : the per-client context pointer which was returned by
|
||||
* openvpn_plugin_client_constructor_v1, if defined.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1)
|
||||
(openvpn_plugin_handle_t handle, void *per_client_context);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_select_initialization_point_v1
|
||||
*
|
||||
* Several different points exist in OpenVPN's initialization sequence where
|
||||
* the openvpn_plugin_open function can be called. While the default is
|
||||
* OPENVPN_PLUGIN_INIT_PRE_DAEMON, this function can be used to select a
|
||||
* different initialization point. For example, if your plugin needs to
|
||||
* return configuration parameters to OpenVPN, use
|
||||
* OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE.
|
||||
*
|
||||
* REQUIRED: NO
|
||||
*
|
||||
* RETURN VALUE:
|
||||
*
|
||||
* An OPENVPN_PLUGIN_INIT_x value.
|
||||
*/
|
||||
#define OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE 1
|
||||
#define OPENVPN_PLUGIN_INIT_PRE_DAEMON 2 /* default */
|
||||
#define OPENVPN_PLUGIN_INIT_POST_DAEMON 3
|
||||
#define OPENVPN_PLUGIN_INIT_POST_UID_CHANGE 4
|
||||
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_select_initialization_point_v1)
|
||||
(void);
|
||||
|
||||
/*
|
||||
* FUNCTION: openvpn_plugin_min_version_required_v1
|
||||
*
|
||||
* This function is called by OpenVPN to query the minimum
|
||||
* plugin interface version number required by the plugin.
|
||||
*
|
||||
* REQUIRED: NO
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* The minimum OpenVPN plugin interface version number necessary to support
|
||||
* this plugin.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_min_version_required_v1)
|
||||
(void);
|
||||
|
||||
/*
|
||||
* Deprecated functions which are still supported for backward compatibility.
|
||||
*/
|
||||
|
||||
OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v1)
|
||||
(unsigned int *type_mask,
|
||||
const char *argv[],
|
||||
const char *envp[]);
|
||||
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v1)
|
||||
(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPENVPN_PLUGIN_H_ */
|
||||
Submodule client/android/cpp/openvpn3 deleted from dd6e82ba9f
@@ -1,40 +0,0 @@
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "jniglue.h"
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
#ifndef NDEBUG
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "Loading openvpn native library $id$ compiled on " __DATE__ " " __TIME__ );
|
||||
#endif
|
||||
return JNI_VERSION_1_2;
|
||||
}
|
||||
|
||||
|
||||
void android_openvpn_log(int level,const char* prefix,const char* prefix_sep,const char* m1)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_DEBUG,"openvpn","%s%s%s",prefix,prefix_sep,m1);
|
||||
}
|
||||
|
||||
|
||||
//! Hack to get the current installed ABI of the libraries. See also https://github.com/schwabe/ics-openvpn/issues/391
|
||||
jstring Java_de_blinkt_openvpn_core_NativeUtils_getJNIAPI(JNIEnv *env, jclass jo)
|
||||
{
|
||||
|
||||
return (*env)->NewStringUTF(env, TARGET_ARCH_ABI);
|
||||
}
|
||||
|
||||
jstring Java_de_blinkt_openvpn_core_NativeUtils_getOpenVPN2GitVersion(JNIEnv *env, jclass jo)
|
||||
{
|
||||
|
||||
return (*env)->NewStringUTF(env, OPENVPN2_GIT_REVISION);
|
||||
}
|
||||
|
||||
jstring Java_de_blinkt_openvpn_core_NativeUtils_getOpenVPN3GitVersion(JNIEnv *env, jclass jo)
|
||||
{
|
||||
|
||||
return (*env)->NewStringUTF(env, OPENVPN3_GIT_REVISION);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// jniglue.h
|
||||
// xcopenvpn
|
||||
//
|
||||
// Created by Arne Schwabe on 29.03.12.
|
||||
// Copyright (c) 2012 Universität Paderborn. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef xcopenvpn_jniglue_h
|
||||
#define xcopenvpn_jniglue_h
|
||||
void android_openvpn_log(int level,const char* prefix,const char* prefix_sep,const char* m1);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int jniThrowException(JNIEnv* env, const char* className, const char* msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,146 +0,0 @@
|
||||
/* Adapted from OpenSSL's rsa_pss.c from OpenSSL 3.0.1 */
|
||||
|
||||
/*
|
||||
* Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
#include "jni.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
static const unsigned char zeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static char opensslerr[1024];
|
||||
extern "C" jbyteArray Java_de_blinkt_openvpn_core_NativeUtils_rsapss(JNIEnv *env,
|
||||
jclass,
|
||||
jint hashtype,
|
||||
jint MSBits,
|
||||
jint rsa_size,
|
||||
jbyteArray from) {
|
||||
|
||||
/*
|
||||
unsigned char *EM,
|
||||
const unsigned char *mHash,
|
||||
const EVP_MD *Hash, const EVP_MD *mgf1Hash,
|
||||
int sLen)
|
||||
*/
|
||||
|
||||
jbyte *data = env->GetByteArrayElements(from, nullptr);
|
||||
int datalen = env->GetArrayLength(from);
|
||||
|
||||
const auto *mHash = reinterpret_cast<const unsigned char *>(data);
|
||||
|
||||
const EVP_MD *Hash;
|
||||
|
||||
if (hashtype == 0) {
|
||||
Hash = EVP_md5();
|
||||
} else if (hashtype == 1) {
|
||||
Hash = EVP_sha1();
|
||||
} else if (hashtype == 2) {
|
||||
Hash = EVP_sha224();
|
||||
} else if (hashtype == 3) {
|
||||
Hash = EVP_sha256();
|
||||
} else if (hashtype == 4) {
|
||||
Hash = EVP_sha384();
|
||||
} else if (hashtype == 5) {
|
||||
Hash = EVP_sha512();
|
||||
}
|
||||
|
||||
const EVP_MD *mgf1Hash = Hash;
|
||||
|
||||
int ret = 0;
|
||||
int maskedDBLen, emLen;
|
||||
unsigned char *H, *salt = nullptr, *p;
|
||||
EVP_MD_CTX *ctx = nullptr;
|
||||
|
||||
int hLen = EVP_MD_get_size(Hash);
|
||||
int sLen = hLen; /* RSA_PSS_SALTLEN_DIGEST */
|
||||
|
||||
std::array<unsigned char, 2048> buf{};
|
||||
unsigned char *EM = buf.data();
|
||||
|
||||
if (hLen < 0)
|
||||
goto err;
|
||||
|
||||
emLen = rsa_size;
|
||||
if (MSBits == 0) {
|
||||
*EM++ = 0;
|
||||
emLen--;
|
||||
}
|
||||
if (emLen < hLen + 2) {
|
||||
goto err;
|
||||
}
|
||||
if (sLen == RSA_PSS_SALTLEN_MAX) {
|
||||
sLen = emLen - hLen - 2;
|
||||
} else if (sLen > emLen - hLen - 2) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sLen > 0) {
|
||||
salt = (unsigned char *) OPENSSL_malloc(sLen);
|
||||
if (salt == nullptr) {
|
||||
goto err;
|
||||
}
|
||||
if (RAND_bytes_ex(nullptr, salt, sLen, 0) <= 0)
|
||||
goto err;
|
||||
}
|
||||
maskedDBLen = emLen - hLen - 1;
|
||||
H = EM + maskedDBLen;
|
||||
ctx = EVP_MD_CTX_new();
|
||||
if (ctx == nullptr)
|
||||
goto err;
|
||||
if (!EVP_DigestInit_ex(ctx, Hash, nullptr)
|
||||
|| !EVP_DigestUpdate(ctx, zeroes, sizeof(zeroes))
|
||||
|| !EVP_DigestUpdate(ctx, mHash, hLen))
|
||||
goto err;
|
||||
if (sLen && !EVP_DigestUpdate(ctx, salt, sLen))
|
||||
goto err;
|
||||
if (!EVP_DigestFinal_ex(ctx, H, nullptr))
|
||||
goto err;
|
||||
|
||||
/* Generate dbMask in place then perform XOR on it */
|
||||
if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash))
|
||||
goto err;
|
||||
|
||||
p = EM;
|
||||
|
||||
/*
|
||||
* Initial PS XORs with all zeroes which is a NOP so just update pointer.
|
||||
* Note from a test above this value is guaranteed to be non-negative.
|
||||
*/
|
||||
p += emLen - sLen - hLen - 2;
|
||||
*p++ ^= 0x1;
|
||||
if (sLen > 0) {
|
||||
for (int i = 0; i < sLen; i++)
|
||||
*p++ ^= salt[i];
|
||||
}
|
||||
if (MSBits)
|
||||
EM[0] &= 0xFF >> (8 - MSBits);
|
||||
|
||||
/* H is already in place so just set final 0xbc */
|
||||
|
||||
EM[emLen - 1] = 0xbc;
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
EVP_MD_CTX_free(ctx);
|
||||
OPENSSL_clear_free(salt, (size_t) sLen); /* salt != NULL implies sLen > 0 */
|
||||
|
||||
|
||||
jbyteArray jb;
|
||||
|
||||
jb = env->NewByteArray(emLen);
|
||||
|
||||
env->SetByteArrayRegion(jb, 0, emLen, (jbyte *) EM);
|
||||
|
||||
return jb;
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
/*
|
||||
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* ====================================================================
|
||||
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
|
||||
*
|
||||
* Portions of the attached software ("Contribution") are developed by
|
||||
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
|
||||
*
|
||||
* The Contribution is licensed pursuant to the OpenSSL open source
|
||||
* license provided above.
|
||||
*
|
||||
* The ECDH and ECDSA speed test software is originally written by
|
||||
* Sumit Gupta of Sun Microsystems Laboratories.
|
||||
*
|
||||
*/
|
||||
|
||||
// Modified by Arne Schwabe to give a simple openssl evp speed java api
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/times.h>
|
||||
#include <linux/if.h>
|
||||
#include <android/log.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "jniglue.h"
|
||||
#include <android/log.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/async.h>
|
||||
#include <openssl/provider.h>
|
||||
|
||||
|
||||
/* This file just contains code thrown together until it works */
|
||||
|
||||
|
||||
#undef SECONDS
|
||||
#define SECONDS 3
|
||||
#define PRIME_SECONDS 10
|
||||
#define RSA_SECONDS 10
|
||||
#define DSA_SECONDS 10
|
||||
#define ECDSA_SECONDS 10
|
||||
#define ECDH_SECONDS 10
|
||||
|
||||
|
||||
typedef struct loopargs_st {
|
||||
unsigned char *buf;
|
||||
unsigned char *buf2;
|
||||
unsigned char *buf_malloc;
|
||||
unsigned char *buf2_malloc;
|
||||
unsigned int siglen;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
HMAC_CTX *hctx;
|
||||
} loopargs_t;
|
||||
|
||||
#undef BUFSIZE
|
||||
#define BUFSIZE (1024*16+1)
|
||||
#define MAX_MISALIGNMENT 63
|
||||
|
||||
|
||||
#define MAX_BLOCK_SIZE 128
|
||||
static unsigned char iv[2 * MAX_BLOCK_SIZE / 8];
|
||||
|
||||
#define SIZE_NUM 7
|
||||
static const int lengths[SIZE_NUM] = {
|
||||
16, 64, 256, 1024, 1500, 8 * 1024, 16 * 1024
|
||||
};
|
||||
|
||||
static int testnum;
|
||||
|
||||
# define COND(unused_cond) (run && count<0x7fffffff)
|
||||
|
||||
static volatile int run = 0;
|
||||
|
||||
#ifdef SIGALRM
|
||||
# if defined(__STDC__) || defined(sgi) || defined(_AIX)
|
||||
# define SIGRETTYPE void
|
||||
# else
|
||||
# define SIGRETTYPE int
|
||||
# endif
|
||||
|
||||
|
||||
#define START 0
|
||||
#define STOP 1
|
||||
#define TM_START 0
|
||||
#define TM_STOP 1
|
||||
|
||||
static int usertime = 1;
|
||||
|
||||
double app_tminterval(int stop, int usertime)
|
||||
{
|
||||
double ret = 0;
|
||||
struct tms rus;
|
||||
clock_t now = times(&rus);
|
||||
static clock_t tmstart;
|
||||
|
||||
if (usertime)
|
||||
now = rus.tms_utime;
|
||||
|
||||
if (stop == TM_START)
|
||||
tmstart = now;
|
||||
else {
|
||||
long int tck = sysconf(_SC_CLK_TCK);
|
||||
ret = (now - tmstart) / (double)tck;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static double Time_F(int s)
|
||||
{
|
||||
double ret = app_tminterval(s, usertime);
|
||||
if (s == STOP)
|
||||
alarm(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static long save_count = 0;
|
||||
static int decrypt = 0;
|
||||
static int EVP_Update_loop(void *args)
|
||||
{
|
||||
loopargs_t *tempargs = *(loopargs_t **)args;
|
||||
unsigned char *buf = tempargs->buf;
|
||||
EVP_CIPHER_CTX *ctx = tempargs->ctx;
|
||||
int outl, count;
|
||||
|
||||
if (decrypt)
|
||||
for (count = 0; COND(nb_iter); count++)
|
||||
EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]);
|
||||
else
|
||||
for (count = 0; COND(nb_iter); count++)
|
||||
EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]);
|
||||
if (decrypt)
|
||||
EVP_DecryptFinal_ex(ctx, buf, &outl);
|
||||
else
|
||||
EVP_EncryptFinal_ex(ctx, buf, &outl);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const EVP_MD *evp_md = NULL;
|
||||
static int EVP_Digest_loop(void *args)
|
||||
{
|
||||
loopargs_t *tempargs = *(loopargs_t **)args;
|
||||
unsigned char *buf = tempargs->buf;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
int count;
|
||||
|
||||
for (count = 0; COND(nb_iter); count++) {
|
||||
if (!EVP_Digest(buf, lengths[testnum], md, NULL, evp_md, NULL))
|
||||
return -1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static int run_benchmark(int async_jobs,
|
||||
int (*loop_function)(void *), loopargs_t *loopargs)
|
||||
{
|
||||
int job_op_count = 0;
|
||||
int total_op_count = 0;
|
||||
int num_inprogress = 0;
|
||||
int error = 0, i = 0, ret = 0;
|
||||
OSSL_ASYNC_FD job_fd = 0;
|
||||
size_t num_job_fds = 0;
|
||||
|
||||
run = 1;
|
||||
|
||||
if (async_jobs == 0) {
|
||||
return loop_function((void *)&loopargs);
|
||||
}
|
||||
return 1234567;
|
||||
}
|
||||
|
||||
|
||||
static void* stop_run(void* arg)
|
||||
{
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "stop run thread started");
|
||||
sleep(3);
|
||||
run=0;
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "stop run thread stopped");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jdoubleArray Java_de_blinkt_openvpn_core_NativeUtils_getOpenSSLSpeed(JNIEnv* env, jclass thiz, jstring algorithm, jint testnumber)
|
||||
{
|
||||
|
||||
OSSL_PROVIDER *legacy;
|
||||
OSSL_PROVIDER *deflt;
|
||||
|
||||
OSSL_LIB_CTX *lib_ctx = OSSL_LIB_CTX_new();
|
||||
|
||||
/* Load Multiple providers into the default (NULL) library context */
|
||||
legacy = OSSL_PROVIDER_load(lib_ctx, "legacy");
|
||||
if (legacy == NULL) {
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "Failed to load Legacy provider\n");
|
||||
return NULL;
|
||||
}
|
||||
deflt = OSSL_PROVIDER_load(lib_ctx, "default");
|
||||
if (deflt == NULL) {
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "Failed to load Default provider\n");
|
||||
OSSL_PROVIDER_unload(legacy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const unsigned char key16[16] = {
|
||||
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
|
||||
0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12
|
||||
};
|
||||
const EVP_CIPHER *evp_cipher = NULL;
|
||||
|
||||
const char* alg = (*env)->GetStringUTFChars( env, algorithm , NULL ) ;
|
||||
|
||||
evp_cipher = EVP_CIPHER_fetch(lib_ctx, alg, NULL);
|
||||
if (evp_cipher == NULL)
|
||||
evp_md = EVP_MD_fetch(lib_ctx, alg, NULL);
|
||||
if (evp_cipher == NULL && evp_md == NULL) {
|
||||
// BIO_printf(bio_err, "%s: %s is an unknown cipher or digest\n", prog, opt_arg());
|
||||
//jniThrowException(env, "java/security/NoSuchAlgorithmException", "Algorithm not found");
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "Algorithm not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
loopargs_t *loopargs = NULL;
|
||||
int loopargs_len = 1;
|
||||
int async_jobs = 0;
|
||||
loopargs = malloc(loopargs_len * sizeof(loopargs_t));
|
||||
memset(loopargs, 0, loopargs_len * sizeof(loopargs_t));
|
||||
|
||||
|
||||
jdoubleArray ret = (*env)->NewDoubleArray(env, 3);
|
||||
|
||||
if (testnum < 0 || testnum >= SIZE_NUM)
|
||||
goto error;
|
||||
|
||||
testnum = testnumber;
|
||||
|
||||
|
||||
for (int i = 0; i < loopargs_len; i++) {
|
||||
int misalign=0;
|
||||
loopargs[i].buf_malloc = malloc((int)BUFSIZE + MAX_MISALIGNMENT + 1);
|
||||
loopargs[i].buf2_malloc = malloc((int)BUFSIZE + MAX_MISALIGNMENT + 1);
|
||||
/* Align the start of buffers on a 64 byte boundary */
|
||||
loopargs[i].buf = loopargs[i].buf_malloc + misalign;
|
||||
loopargs[i].buf2 = loopargs[i].buf2_malloc + misalign;
|
||||
}
|
||||
|
||||
|
||||
int count;
|
||||
double d;
|
||||
if (evp_cipher) {
|
||||
/*
|
||||
* -O3 -fschedule-insns messes up an optimization here!
|
||||
* names[D_EVP] somehow becomes NULL
|
||||
*/
|
||||
|
||||
|
||||
for (int k = 0; k < loopargs_len; k++) {
|
||||
loopargs[k].ctx = EVP_CIPHER_CTX_new();
|
||||
if (decrypt)
|
||||
EVP_DecryptInit_ex(loopargs[k].ctx, evp_cipher, NULL, key16, iv);
|
||||
else
|
||||
EVP_EncryptInit_ex(loopargs[k].ctx, evp_cipher, NULL, key16, iv);
|
||||
EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0);
|
||||
}
|
||||
|
||||
Time_F(START);
|
||||
pthread_t timer_thread;
|
||||
|
||||
if (pthread_create(&timer_thread, NULL, stop_run, NULL))
|
||||
goto error;
|
||||
|
||||
count = run_benchmark(async_jobs, EVP_Update_loop, loopargs);
|
||||
d = Time_F(STOP);
|
||||
for (int k = 0; k < loopargs_len; k++) {
|
||||
EVP_CIPHER_CTX_free(loopargs[k].ctx);
|
||||
}
|
||||
}
|
||||
if (evp_md) {
|
||||
pthread_t timer_thread;
|
||||
if (pthread_create(&timer_thread, NULL, stop_run, NULL))
|
||||
{
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"openvpn", "creating thread failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
Time_F(START);
|
||||
count = run_benchmark(async_jobs, EVP_Digest_loop, loopargs);
|
||||
d = Time_F(STOP);
|
||||
}
|
||||
|
||||
// Save results in hacky way
|
||||
double results[] = {(double) lengths[testnum], (double) count, d};
|
||||
|
||||
|
||||
(*env)->SetDoubleArrayRegion(env, ret, 0, 3, results);
|
||||
// print_result(D_EVP, testnum, count, d);
|
||||
|
||||
OSSL_LIB_CTX_free(lib_ctx);
|
||||
free(loopargs);
|
||||
return ret;
|
||||
error:
|
||||
for (int k = 0; k < loopargs_len; k++) {
|
||||
EVP_CIPHER_CTX_free(loopargs[k].ctx);
|
||||
}
|
||||
free(loopargs);
|
||||
|
||||
OSSL_LIB_CTX_free(lib_ctx);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
FUNCTION(PREPEND var prefix)
|
||||
SET(listVar "")
|
||||
FOREACH(f ${ARGN})
|
||||
LIST(APPEND listVar "${prefix}/${f}")
|
||||
ENDFOREACH(f)
|
||||
SET(${var} "${listVar}" PARENT_SCOPE)
|
||||
ENDFUNCTION(PREPEND)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable → Regular
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,15 +1,14 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
//apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
//apply plugin: 'com.novoda.bintray-release'
|
||||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||
compileSdkVersion 30
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 31
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
|
||||
@@ -29,9 +28,6 @@ android {
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
}
|
||||
}
|
||||
|
||||
androidExtensions {
|
||||
@@ -46,44 +42,29 @@ dependencies {
|
||||
implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.30-M1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
|
||||
|
||||
implementation "androidx.core:core-ktx:1.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-core-ktx:2.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
|
||||
implementation "androidx.room:room-runtime:2.5.0" // runtime
|
||||
implementation "androidx.preference:preference:1.2.0"
|
||||
implementation "androidx.room:room-runtime:$roomVersion" // runtime
|
||||
implementation "androidx.preference:preference:1.1.0"
|
||||
implementation "androidx.work:work-runtime-ktx:2.7.1"
|
||||
implementation "androidx.browser:browser:1.3.0-alpha01"
|
||||
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
|
||||
implementation "com.google.android.material:material:1.2.0-alpha05"
|
||||
implementation "androidx.work:work-multiprocess:2.7.1"
|
||||
|
||||
implementation "com.android.support:support-compat:27.0.2"
|
||||
implementation "androidx.activity:activity:1.6.1"
|
||||
implementation "androidx.fragment:fragment:1.3.0"
|
||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||
implementation "com.google.android.gms:play-services-oss-licenses:17.0.0"
|
||||
implementation "com.google.code.gson:gson:2.10.1"
|
||||
implementation "com.google.firebase:firebase-analytics-ktx:21.2.0"
|
||||
implementation "com.google.firebase:firebase-crashlytics:18.3.3"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.0-rc02"
|
||||
implementation "androidx.core:core-ktx:1.9.0"
|
||||
implementation "com.google.code.gson:gson:2.8.5"
|
||||
|
||||
implementation "dnsjava:dnsjava:3.5.2"
|
||||
implementation "dnsjava:dnsjava:2.1.9"
|
||||
implementation "org.connectbot.jsocks:jsocks:1.0.0"
|
||||
implementation "com.afollestad.material-dialogs:core:2.6.0"
|
||||
// api "com.takisoft.preferencex:preferencex:1.0.0"
|
||||
implementation 'com.takisoft.preferencex:preferencex:1.1.0'
|
||||
|
||||
api 'org.connectbot.jsocks:jsocks:1.0.0'
|
||||
api 'androidx.fragment:fragment-ktx:1.5.5'
|
||||
|
||||
kapt "androidx.room:room-compiler:2.5.0"
|
||||
|
||||
kapt "androidx.room:room-compiler:$roomVersion"
|
||||
kapt "androidx.lifecycle:lifecycle-compiler:2.4.0"
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "94322785672",
|
||||
"firebase_url": "https://amnezia-c6715-default-rtdb.europe-west1.firebasedatabase.app",
|
||||
"project_id": "amnezia-c6715",
|
||||
"storage_bucket": "amnezia-c6715.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:94322785672:android:ed42ab188d6edecf754e3d",
|
||||
"android_client_info": {
|
||||
"package_name": "org.amnezia.vpn"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "94322785672-p3q726tro36fr9nluj45l35gqv6nhjsq.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyCvblU4w_NZbWk9bNQc-KGmg-WODjbb308"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "94322785672-p3q726tro36fr9nluj45l35gqv6nhjsq.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:94322785672:android:95e8779ff76d6641754e3d",
|
||||
"android_client_info": {
|
||||
"package_name": "org.amnezia.vpn.shadowsocks.core"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "94322785672-p3q726tro36fr9nluj45l35gqv6nhjsq.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyCvblU4w_NZbWk9bNQc-KGmg-WODjbb308"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "94322785672-p3q726tro36fr9nluj45l35gqv6nhjsq.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/build
|
||||
@@ -1,80 +0,0 @@
|
||||
* 2.0.1:
|
||||
* Moved `AlertDialogFragment` and related utilities to `fragment` package, with support for Fragment Result API from AndroidX Fragment 1.3.
|
||||
* Dependency updates:
|
||||
- `androidx.fragment:fragment-ktx:1.3.3`;
|
||||
- `com.google.android.material:material:1.3.0`;
|
||||
- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32`.
|
||||
* 2.0.0:
|
||||
* Deprecated passing `-V` and `--fast-open` to plugin.
|
||||
Please find `__android_vpn` option passed via plugin options.
|
||||
* Dependency updates:
|
||||
- `androidx.core:core-ktx:1.3.2`;
|
||||
- `androidx.drawerlayout:drawerlayout:1.1.1`;
|
||||
- `com.google.android.material:material:1.2.1`;
|
||||
- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10`.
|
||||
* 1.3.4:
|
||||
* Optional new metadata `com.github.shadowsocks.plugin.id.aliases` for plugin ID aliases;
|
||||
(see doc for `PluginContract.METADATA_KEY_ID_ALIASES` and main documentation "Plugin ID Aliasing" for more information)
|
||||
* Please use `android:path` instead of `android:pathPrefix`, sample code in documentations have been updated to reflect this recommendation.
|
||||
* Added missing documentation regarding direct boot support.
|
||||
Please add `android:directBootAware="true"` with proper support for your `provider` if possible.
|
||||
* You can now use `android:resources` on `meta-data` tags. (main/host app update required, however, you should never use dynamic resources)
|
||||
* Fix occasional crash in `AlertDialogFragment`.
|
||||
* Translation updates.
|
||||
* Dependency updates:
|
||||
- `androidx.core:core-ktx:1.2.0`;
|
||||
- `com.google.android.material:material:1.1.0`.
|
||||
* 1.3.3:
|
||||
* Fix a build script issue.
|
||||
* 1.3.2:
|
||||
* Fix first key-value pair disappearing with null value. (#2391)
|
||||
* Dependency updates:
|
||||
- `androidx.core:core-ktx:1.1.0`;
|
||||
- `com.google.android.material:material:1.1.0-rc01`;
|
||||
- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61`.
|
||||
* 1.3.1:
|
||||
* New theme resource `Theme.Shadowsocks.Immersive` for better Android Q-esque translucent navigation bars.
|
||||
This is an opt-in feature.
|
||||
Please add `android:theme="@style/Theme.Shadowsocks.Immersive"` to your `<activity>` to enable this theme.
|
||||
* New color resources `light_*` and `dark_*` for passing to custom tabs;
|
||||
* Dependency updates:
|
||||
- `androidx.core:core-ktx:1.1.0-rc03`;
|
||||
- `androidx.drawerlayout:drawerlayout:1.1.0-alpha03`;
|
||||
- `com.google.android.material:material:1.1.0-alpha09`;
|
||||
- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.41`.
|
||||
* 1.3.0:
|
||||
* Optional new metadata `com.github.shadowsocks.plugin.executable_path` for even faster initialization;
|
||||
(see doc for `PluginContract.METADATA_KEY_EXECUTABLE_PATH` for more information)
|
||||
* Breaking API change: `val AlertDialogFragment.ret: Ret?` => `fun AlertDialogFragment.ret(which: Int): Ret?`;
|
||||
(nothing needs to be done if you are not using this API)
|
||||
* Dependency updates:
|
||||
- Now targeting API 29;
|
||||
- `androidx.core:core-ktx:1.1.0-rc01`;
|
||||
- `com.google.android.material:material:1.1.0-alpha07`;
|
||||
- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.40`.
|
||||
* 1.2.0:
|
||||
* New helper class `AlertDialogFragment` for creating `AlertDialog` that persists through configuration changes;
|
||||
* Dependency update: `com.google.android.material:material:1.1.0-alpha03`.
|
||||
* 1.1.0:
|
||||
* Having control characters in plugin options is no longer allowed.
|
||||
If this breaks your plugin, you are doing it wrong.
|
||||
* New helper method: `PluginOptions.putWithDefault`.
|
||||
* 1.0.0:
|
||||
* BREAKING CHANGE: Plugins developed using this version and forward require shadowsocks-android 4.6.5 or higher.
|
||||
* `PathProvider` now takes `Int` instead of `String` for file modes;
|
||||
* Refactor to AndroidX;
|
||||
* No longer depends on preference libraries.
|
||||
* 0.1.1:
|
||||
* Rewritten in Kotlin;
|
||||
* Fix assert not working;
|
||||
* Min API 21;
|
||||
* Update support library version to 27.1.1.
|
||||
* 0.0.4:
|
||||
* Enlarge text size of number pickers;
|
||||
* Update support library version to 26.0.0.
|
||||
* 0.0.3:
|
||||
* Update support library version to 25.2.0.
|
||||
* 0.0.2:
|
||||
* Add `getOrDefault` to `PluginOptions`;
|
||||
* Update support library version to 25.1.1.
|
||||
* 0.0.1: Initial release.
|
||||
@@ -1,167 +0,0 @@
|
||||
# shadowsocks-android plugin framework
|
||||
|
||||
[Documentation](doc.md) | [Change log](CHANGES.md)
|
||||
|
||||
Support library for easier development on [shadowsocks
|
||||
plugin](https://github.com/shadowsocks/shadowsocks-org/issues/28) for Android. Also includes some
|
||||
useful resources to easily get consistent styling with the main app.
|
||||
|
||||
## Official plugins
|
||||
|
||||
These are some plugins ready to use on shadowsocks-android.
|
||||
|
||||
* [v2ray](https://github.com/shadowsocks/v2ray-plugin-android)
|
||||
* [kcptun](https://github.com/shadowsocks/kcptun-android/releases)
|
||||
* [simple-obfs](https://github.com/shadowsocks/simple-obfs-android/releases)
|
||||
|
||||
## Developer's guide
|
||||
|
||||
This library is designed with Java interoperability in mind so theoretically you can use this
|
||||
library with other languages and/or build tools but there isn't documentation for that yet. This
|
||||
guide is written for Scala + SBT. Contributions are welcome.
|
||||
|
||||
### Package name
|
||||
|
||||
There are no arbitrary restrictions/requirements on package name, component name and content
|
||||
provider authority, but you're suggested to follow the format in this documentations. For package
|
||||
name, use `com.github.shadowsocks.plugin.$PLUGIN_ID` if it only contains a single plugin to
|
||||
prevent duplicated plugins. In some places hyphens are not accepted, for example package name. In
|
||||
that case, hyphens `-` should be changed into underscores `_`. For example, the package name for
|
||||
`obfs-local` would probably be `com.github.shadowsocks.plugin.obfs_local`.
|
||||
|
||||
### Add dependency
|
||||
|
||||
First you need to add this library to your dependencies.
|
||||
This library is written mostly in Kotlin but can also work with Java-only projects:
|
||||
|
||||
```gradle
|
||||
implementation 'com.github.shadowsocks:plugin:$LATEST_VERSION'
|
||||
```
|
||||
|
||||
### Native binary configuration
|
||||
|
||||
First you need to get your native binary compiling on Android platform.
|
||||
|
||||
* [Sample project for C](https://github.com/shadowsocks/simple-obfs-android/tree/4f82c4a4e415d666e70a7e2e60955cb0d85c1615);
|
||||
* [Sample project for Go](https://github.com/shadowsocks/v2ray-plugin-android/tree/172bd4cec0276112828614482fb646b79dbf1540).
|
||||
|
||||
In addition to functionalities of a normal plugin, it has to support these additional options:
|
||||
|
||||
* `__android_vpn`: VPN mode.
|
||||
In this case, the plugin should pass all file descriptors that needs protecting from VPN connections (i.e. its traffic will not be forwarded through the VPN) through an ancillary message to `./protect_path`.
|
||||
|
||||
### Implement a binary provider
|
||||
|
||||
You just need to implement two or three methods. For example for `v2ray`:
|
||||
|
||||
```kotlin
|
||||
class BinaryProvider : NativePluginProvider() {
|
||||
override fun populateFiles(provider: PathProvider) {
|
||||
provider.addPath("v2ray", 0b111101101)
|
||||
// add additional files here
|
||||
}
|
||||
|
||||
// remove this method to disable fast mode, read more in the documentation
|
||||
override fun getExecutable() = context!!.applicationInfo.nativeLibraryDir + "/libv2ray.so"
|
||||
|
||||
override fun openFile(uri: Uri): ParcelFileDescriptor = when (uri.path) {
|
||||
"/v2ray" -> ParcelFileDescriptor.open(File(getExecutable()), ParcelFileDescriptor.MODE_READ_ONLY)
|
||||
// handle additional files here
|
||||
else -> throw FileNotFoundException()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then add it to your manifest:
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<provider android:name=".BinaryProvider"
|
||||
android:exported="true"
|
||||
android:directBootAware="true"
|
||||
android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.id"
|
||||
android:value="$PLUGIN_ID"/>
|
||||
<!-- Optional: default is empty -->
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.default_config"
|
||||
android:value="dummy=default;plugin=options"/>
|
||||
<!-- Optional: remove to disable faster mode, read more in the documentation -->
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.executable_path"
|
||||
android:value="$PATH_TO_EXECUTABLE_RELATIVE_TO_NATIVE_LIB_DIR"/>
|
||||
</provider>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
### Add user interfaces
|
||||
|
||||
You should add to your plugin app a configuration activity or a help activity or both if you're
|
||||
going to use `ConfigurationActivity.fallbackToManualEditor`.
|
||||
|
||||
#### Configuration activity
|
||||
|
||||
This is used if found instead of a manual input dialog when user clicks "Configure..." in the main
|
||||
app. This gives you maximum freedom of the user interface. To implement this, you need to extend
|
||||
`ConfigurationActivity` and you will get current options via
|
||||
`onInitializePluginOptions(PluginOptions)` and you can invoke `saveChanges(PluginOptions)` or
|
||||
`discardChanges()` before `finish()` or `fallbackToManualEditor()`. Then add it to your manifest:
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<activity android:name=".ConfigActivity">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_CONFIGURE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
#### Help activity/callback
|
||||
|
||||
This is started when user taps "?" in manual editor. To implement this, you need to extend
|
||||
`HelpCallback` if you want a simple dialog with help message as `CharSequence` or `HelpActivity`
|
||||
if you want to provide custom user interface, implement the required methods, then add it to your
|
||||
manifest:
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<activity android:name=".HelpActivity">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_HELP"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
Great. Now your plugin is ready to use.
|
||||
@@ -1,20 +0,0 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("com.vanniktech.maven.publish")
|
||||
kotlin("android")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
setupCommon()
|
||||
|
||||
android {
|
||||
namespace = "com.github.shadowsocks.plugin"
|
||||
lint.informational += "GradleDependency"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api("androidx.core:core-ktx:1.7.0")
|
||||
api("androidx.fragment:fragment-ktx:1.5.5")
|
||||
api("com.google.android.material:material:1.6.0")
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
# Overview
|
||||
|
||||
Plugin should be bundled as an apk. `$PLUGIN_ID` in this documentation corresponds to the
|
||||
executable name for the plugin in order to be cross-platform, e.g. `obfs-local`. An apk can have
|
||||
more than one plugins bundled. We don't care as long as they have different `$PLUGIN_ID`. For
|
||||
duplicated plugin ID, host should refuse to start.
|
||||
|
||||
There are no arbitrary restrictions/requirements on package name, component name and content
|
||||
provider authority, but you're suggested to follow the format in this documentations. For package
|
||||
name, use `com.github.shadowsocks.plugin.$PLUGIN_ID` if it only contains a single plugin to prevent
|
||||
duplicated plugins. In some places hyphens are not accepted, for example package name. In that
|
||||
case, hyphens `-` should be changed into underscores `_`. For example, the package name for
|
||||
`obfs-local` would probably be `com.github.shadowsocks.plugin.obfs_local`.
|
||||
|
||||
It's advised to use this library for easier development, but you're free to start from scratch following this
|
||||
documentation.
|
||||
|
||||
# Plugin configuration
|
||||
|
||||
Plugins get their args configured via one of the following two options:
|
||||
|
||||
* A configuration activity;
|
||||
([example](https://github.com/shadowsocks/simple-obfs-android/tree/4f82c4a4e415d666e70a7e2e60955cb0d85c1615))
|
||||
* If no configuration activity is found or the activity requests the fallback mode, the fallback
|
||||
mode will be used: user manual input and optional help message.
|
||||
([example](https://github.com/shadowsocks/kcptun-android/tree/41f42077e177618553417c16559784a51e9d8c4c))
|
||||
|
||||
Your user interface need not be consistent with shadowsocks-android styling - you don't need to use
|
||||
preferences UI at all if you don't feel like it - however it's recommended to use Material Design
|
||||
at minimum.
|
||||
|
||||
## Configuration activity
|
||||
|
||||
If the plugin provides a configuration activity, it will be started when user picks your plugin and
|
||||
taps configure. It:
|
||||
|
||||
* MUST have action: `com.github.shadowsocks.plugin.ACTION_CONFIGURE`;
|
||||
* MUST have category: `android.intent.category.DEFAULT`;
|
||||
* MUST be able to receive data URI `plugin://com.github.shadowsocks/$PLUGIN_ID`;
|
||||
* SHOULD parse string extra `com.github.shadowsocks.plugin.EXTRA_OPTIONS` (all options as a single
|
||||
string) and display the current options;
|
||||
* SHOULD distinguish between server settings and feature settings in some way, e.g. for
|
||||
`obfs-local`, `obfs` is a server setting and `obfs_host` is a feature setting;
|
||||
* On finish, it SHOULD return one of the following results:
|
||||
- `RESULT_OK = 0`: In this case it MUST return the data Intent with the new
|
||||
`com.github.shadowsocks.plugin.EXTRA_OPTIONS`;
|
||||
- `RESULT_CANCELED = -1`: Nothing will be changed;
|
||||
- `RESULT_FALLBACK = 1`: Fallback mode is requested and the host should display the fallback
|
||||
editor.
|
||||
|
||||
This corresponds to `com.github.shadowsocks.plugin.ConfigurationActivity` in the plugin library.
|
||||
Here's what a proper configuration activity usually should look like in `AndroidManifest.xml`:
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<activity android:name=".ConfigActivity">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_CONFIGURE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
## Help activity/callback
|
||||
|
||||
If the plugin doesn't provide a configuration activity, it's highly recommended to provide a help
|
||||
message in the form of an Activity. It:
|
||||
|
||||
* MUST have action: `com.github.shadowsocks.plugin.ACTION_HELP`;
|
||||
* MUST have category: `android.intent.category.DEFAULT`;
|
||||
* MUST be able to receive data URI `plugin://com.github.shadowsocks/$PLUGIN_ID`;
|
||||
* CAN parse string extra `com.github.shadowsocks.plugin.EXTRA_OPTIONS` and display some more
|
||||
relevant information;
|
||||
* SHOULD parse `@NightMode` int extra `com.github.shadowsocks.plugin.EXTRA_NIGHT_MODE` and act
|
||||
accordingly;
|
||||
* SHOULD either:
|
||||
- Be invisible and return help message with CharSequence extra
|
||||
`com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE` in the data intent with `RESULT_OK`; (in this
|
||||
case, a simple dialog will be shown containing the message)
|
||||
- Be visible and return `RESULT_CANCELED`.
|
||||
* SHOULD distinguish between server settings and feature settings in some way, e.g. for
|
||||
`simple_obfs`, `obfs` is a server setting and `obfs_host` is a feature setting.
|
||||
|
||||
This corresponds to `com.github.shadowsocks.plugin.HelpActivity` or
|
||||
`com.github.shadowsocks.plugin.HelpCallback` in the plugin library. Here's what a proper help
|
||||
activity/callback usually should look like in `AndroidManifest.xml`:
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<activity android:name=".HelpActivity">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_HELP"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
# Plugin implementation
|
||||
|
||||
Every plugin can be either in native mode or JVM mode.
|
||||
|
||||
## Native mode
|
||||
|
||||
In native mode, plugins are provided as native executables and `shadowsocks-libev`'s plugin mode
|
||||
will be used.
|
||||
|
||||
Every native mode plugin MUST have a content provider to provide the native executables (since they
|
||||
can exceed 1M which is the limit of Intent size) that:
|
||||
|
||||
* MUST have `android:label` and `android:icon`; (may be inherited from parent `application`)
|
||||
* SHOULD have `android:directBootAware="true"` with proper support if possible;
|
||||
* MUST have an intent filter with action `com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN`;
|
||||
(used for discovering plugins)
|
||||
* MUST have meta-data `com.github.shadowsocks.plugin.id` with string value `$PLUGIN_ID` or a string resource;
|
||||
* MUST have an intent filter with action `com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN` and
|
||||
data `plugin://com.github.shadowsocks/$PLUGIN_ID`; (used for configuring plugin)
|
||||
* CAN have meta-data `com.github.shadowsocks.plugin.default_config` with string value or a string resource, default is empty;
|
||||
* MUST implement `query` that returns the file list which MUST include `$PLUGIN_ID` when having
|
||||
these as arguments:
|
||||
- `uri = "content://$authority_of_your_provider`;
|
||||
- `projection = ["path", "mode"]`; (relative path, for example `obfs-local`; file mode as integer, for
|
||||
example `0b110100100`)
|
||||
- `selection = null`;
|
||||
- `selectionArgs = null`;
|
||||
- `sortOrder = null`;
|
||||
* MUST implement `openFile` that for files returned in `query`, `openFile` with `mode = "r"` returns
|
||||
a valid `ParcelFileDescriptor` for reading. For example, `uri` can be
|
||||
`content://com.github.shadowsocks.plugin.kcptun/kcptun`.
|
||||
|
||||
This corresponds to `com.github.shadowsocks.plugin.NativePluginProvider` in the plugin library.
|
||||
Here's what a proper native plugin provider usually should look like in `AndroidManifest.xml`:
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<provider android:name=".BinaryProvider"
|
||||
android:exported="true"
|
||||
android:directBootAware="true"
|
||||
android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER"
|
||||
tools:ignore="ExportedContentProvider">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.id"
|
||||
android:value="$PLUGIN_ID"/>
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.default_config"
|
||||
android:value="dummy=default;plugin=options"/>
|
||||
</provider>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
## Native mode without binary copying
|
||||
|
||||
If your plugin binary executable can run in place, you can support native mode without binary
|
||||
copying. To support this mode, your `ContentProvider` must first support native mode with binary
|
||||
copying (this will be used if the fast routine fails) and:
|
||||
|
||||
* MUST implement `call` that returns absolute path to the entry executable as
|
||||
`com.github.shadowsocks.plugin.EXTRA_ENTRY` when having `method = "shadowsocks:getExecutable"`;
|
||||
(`com.github.shadowsocks.plugin.EXTRA_OPTIONS` is provided in extras as well just in case you
|
||||
need them)
|
||||
* SHOULD define `android:installLocation="internalOnly"` for `<manifest>` in AndroidManifest.xml;
|
||||
* SHOULD define `android:extractNativeLibs="true"` for `<application>` in AndroidManifest.xml;
|
||||
|
||||
If you don't plan to support this mode, you can just throw `UnsupportedOperationException` when
|
||||
being invoked. It will fallback to the slow routine automatically.
|
||||
|
||||
### Native mode without binary copying and setup
|
||||
|
||||
Additionally, if your plugin only needs to supply the path of your executable without doing any extra setup work,
|
||||
you can use an additional `meta-data` with name `com.github.shadowsocks.plugin.executable_path`
|
||||
to supply executable path to your native binary.
|
||||
This allows the host app to launch your plugin without ever launching your app.
|
||||
|
||||
## JVM mode
|
||||
|
||||
This feature hasn't been implemented yet.
|
||||
Please open an issue if you need this.
|
||||
|
||||
# Plugin security
|
||||
|
||||
Plugins are certified using package signatures and shadowsocks-android will consider these
|
||||
signatures as trusted:
|
||||
|
||||
* Signatures by [trusted sources](/mobile/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt#L39)
|
||||
which includes:
|
||||
- @madeye, i.e. the signer of the main repo;
|
||||
- The main repo doesn't contain any other trusted signatures. Third-party forks should add their
|
||||
signatures to this trusted sources if they have plugins signed by them before publishing their
|
||||
source code.
|
||||
* Current package signature, which means:
|
||||
- If you get apk from shadowsocks-android releases or Google Play, this means only apk signed by
|
||||
@madeye will be recognized as trusted.
|
||||
- If you get apk from a third-party fork, all plugins from that developer will get recognized as
|
||||
trusted automatically even if its source code isn't available anywhere online.
|
||||
|
||||
A warning will be shown for untrusted plugins. No arbitrary restrictions will be applied.
|
||||
|
||||
# Plugin platform versioning
|
||||
|
||||
In order to be able to identify compatible and incompatible plugins, [Semantic
|
||||
Versioning](http://semver.org/) will be used.
|
||||
|
||||
>Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
>
|
||||
>1. MAJOR version when you make incompatible API changes,
|
||||
>2. MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
>3. PATCH version when you make backwards-compatible bug fixes.
|
||||
|
||||
Plugin app must include this in their application tag: (which should be automatically included if
|
||||
you are using our library)
|
||||
|
||||
```
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.version"
|
||||
android:value="1.0.0"/>
|
||||
```
|
||||
|
||||
# Plugin ID Aliasing
|
||||
|
||||
To implement plugin ID aliasing, you:
|
||||
|
||||
* MUST define meta-data `com.github.shadowsocks.plugin.id.aliases` in your plugin content provider with `android:value="alias"`,
|
||||
or use `android:resources` to specify a string resource or string array resource for multiple aliases.
|
||||
* MUST be able to be matched by `com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN` when invoked on alias.
|
||||
To do this, you SHOULD use multiple `intent-filter` and use a different `android:path` for each alias.
|
||||
Alternatively, you MAY also use a single `intent-filter` and use `android:pathPattern` to match all your aliases at once.
|
||||
You MUST NOT use `android:pathPrefix` or allow `android:pathPattern` to match undeclared plugin ID/alias as it might create a conflict with other plugins.
|
||||
* SHOULD NOT add or change `intent-filter` for activities to include your aliases -- your plugin ID will always be used.
|
||||
|
||||
For example:
|
||||
```xml
|
||||
<manifest>
|
||||
...
|
||||
<application>
|
||||
...
|
||||
<provider>
|
||||
...
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ID"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
|
||||
<data android:scheme="plugin"
|
||||
android:host="com.github.shadowsocks"
|
||||
android:path="/$PLUGIN_ALIAS"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.id"
|
||||
android:value="$PLUGIN_ID"/>
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.aliases"
|
||||
android:value="$PLUGIN_ALIAS"/>
|
||||
...
|
||||
</provider>
|
||||
...
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
# Android TV
|
||||
|
||||
Android TV client does not invoke configuration activities. Therefore your plugins should automatically work with them.
|
||||
@@ -1,21 +0,0 @@
|
||||
GROUP=com.github.shadowsocks
|
||||
VERSION_NAME=2.0.1
|
||||
|
||||
POM_ARTIFACT_ID=plugin
|
||||
POM_NAME=Shadowsocks Plugin
|
||||
POM_PACKAGING=aar
|
||||
|
||||
POM_DESCRIPTION=SIP003 plugin for Shadowsocks
|
||||
POM_INCEPTION_YEAR=2018
|
||||
|
||||
POM_URL=https://github.com/shadowsocks/shadowsocks-android
|
||||
POM_SCM_URL=https://github.com/shadowsocks/shadowsocks-android
|
||||
POM_SCM_CONNECTION=scm:git:git://github.com/shadowsocks/shadowsocks-android.git
|
||||
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/shadowsocks/shadowsocks-android.git
|
||||
|
||||
POM_LICENCE_NAME=The GNU General Public License v3.0
|
||||
POM_LICENCE_URL=https://www.gnu.org/licenses/gpl-3.0.html
|
||||
POM_LICENCE_DIST=repo
|
||||
|
||||
POM_DEVELOPER_ID=Mygod
|
||||
POM_DEVELOPER_NAME=Mygod Studio
|
||||
@@ -1,7 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:theme="@style/Theme.Shadowsocks">
|
||||
<meta-data android:name="com.github.shadowsocks.plugin.version"
|
||||
android:value="2.0.1"/>
|
||||
</application>
|
||||
</manifest>
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
/**
|
||||
* Based on: https://android.googlesource.com/platform/packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("Related APIs are deprecated in AndroidX", ReplaceWith("fragment.AlertDialogFragment"))
|
||||
abstract class AlertDialogFragment<Arg : Parcelable, Ret : Parcelable> :
|
||||
AppCompatDialogFragment(), DialogInterface.OnClickListener {
|
||||
companion object {
|
||||
private const val KEY_ARG = "arg"
|
||||
private const val KEY_RET = "ret"
|
||||
fun <T : Parcelable> getRet(data: Intent) = data.extras!!.getParcelable<T>(KEY_RET)!!
|
||||
}
|
||||
protected abstract fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener)
|
||||
|
||||
protected val arg by lazy { requireArguments().getParcelable<Arg>(KEY_ARG)!! }
|
||||
protected open fun ret(which: Int): Ret? = null
|
||||
fun withArg(arg: Arg) = apply { arguments = Bundle().apply { putParcelable(KEY_ARG, arg) } }
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog =
|
||||
AlertDialog.Builder(requireContext()).also { it.prepare(this) }.create()
|
||||
|
||||
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||
targetFragment?.onActivityResult(targetRequestCode, which, ret(which)?.let {
|
||||
Intent().replaceExtras(Bundle().apply { putParcelable(KEY_RET, it) })
|
||||
})
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
onClick(dialog, Activity.RESULT_CANCELED)
|
||||
}
|
||||
|
||||
fun show(target: Fragment, requestCode: Int = 0, tag: String = javaClass.simpleName) {
|
||||
setTargetFragment(target, requestCode)
|
||||
showAllowingStateLoss(target.fragmentManager ?: return, tag)
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* Base class for configuration activity. A configuration activity is started when user wishes to configure the
|
||||
* selected plugin. To create a configuration activity, extend this class, implement abstract methods, invoke
|
||||
* `saveChanges(options)` and `discardChanges()` when appropriate, and add it to your manifest like this:
|
||||
*
|
||||
* <pre class="prettyprint"><manifest>
|
||||
* ...
|
||||
* <application>
|
||||
* ...
|
||||
* <activity android:name=".ConfigureActivity">
|
||||
* <intent-filter>
|
||||
* <action android:name="com.github.shadowsocks.plugin.ACTION_CONFIGURE"/>
|
||||
* <category android:name="android.intent.category.DEFAULT"/>
|
||||
* <data android:scheme="plugin"
|
||||
* android:host="com.github.shadowsocks"
|
||||
* android:path="/$PLUGIN_ID"/>
|
||||
* </intent-filter>
|
||||
* </activity>
|
||||
* ...
|
||||
* </application>
|
||||
*</manifest></pre>
|
||||
*/
|
||||
abstract class ConfigurationActivity : OptionsCapableActivity() {
|
||||
/**
|
||||
* Equivalent to setResult(RESULT_CANCELED).
|
||||
*/
|
||||
fun discardChanges() = setResult(Activity.RESULT_CANCELED)
|
||||
|
||||
/**
|
||||
* Equivalent to setResult(RESULT_OK, args_with_correct_format).
|
||||
*
|
||||
* @param options PluginOptions to save.
|
||||
*/
|
||||
fun saveChanges(options: PluginOptions) =
|
||||
setResult(Activity.RESULT_OK, Intent().putExtra(PluginContract.EXTRA_OPTIONS, options.toString()))
|
||||
|
||||
/**
|
||||
* Finish this activity and request manual editor to pop up instead.
|
||||
*/
|
||||
fun fallbackToManualEditor() {
|
||||
setResult(PluginContract.RESULT_FALLBACK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
/**
|
||||
* Base class for a help activity. A help activity is started when user taps help when configuring options for your
|
||||
* plugin. To create a help activity, just extend this class, and add it to your manifest like this:
|
||||
*
|
||||
* <pre class="prettyprint"><manifest>
|
||||
* ...
|
||||
* <application>
|
||||
* ...
|
||||
* <activity android:name=".HelpActivity">
|
||||
* <intent-filter>
|
||||
* <action android:name="com.github.shadowsocks.plugin.ACTION_HELP"/>
|
||||
* <category android:name="android.intent.category.DEFAULT"/>
|
||||
* <data android:scheme="plugin"
|
||||
* android:host="com.github.shadowsocks"
|
||||
* android:path="/$PLUGIN_ID"/>
|
||||
* </intent-filter>
|
||||
* </activity>
|
||||
* ...
|
||||
* </application>
|
||||
*</manifest></pre>
|
||||
*/
|
||||
abstract class HelpActivity : OptionsCapableActivity() {
|
||||
override fun onInitializePluginOptions(options: PluginOptions) { }
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* HelpCallback is an HelpActivity but you just need to produce a CharSequence help message instead of having to
|
||||
* provide UI. To create a help callback, just extend this class, implement abstract methods, and add it to your
|
||||
* manifest following the same procedure as adding a HelpActivity.
|
||||
*/
|
||||
abstract class HelpCallback : HelpActivity() {
|
||||
abstract fun produceHelpMessage(options: PluginOptions): CharSequence
|
||||
|
||||
override fun onInitializePluginOptions(options: PluginOptions) {
|
||||
setResult(RESULT_OK, Intent().putExtra(PluginContract.EXTRA_HELP_MESSAGE, produceHelpMessage(options)))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.ParcelFileDescriptor
|
||||
import androidx.core.os.bundleOf
|
||||
|
||||
/**
|
||||
* Base class for a native plugin provider. A native plugin provider offers read-only access to files that are required
|
||||
* to run a plugin, such as binary files and other configuration files. To create a native plugin provider, extend this
|
||||
* class, implement the abstract methods, and add it to your manifest like this:
|
||||
*
|
||||
* <pre class="prettyprint"><manifest>
|
||||
* ...
|
||||
* <application>
|
||||
* ...
|
||||
* <provider android:name="com.github.shadowsocks.$PLUGIN_ID.BinaryProvider"
|
||||
* android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID.BinaryProvider">
|
||||
* <intent-filter>
|
||||
* <category android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" />
|
||||
* </intent-filter>
|
||||
* </provider>
|
||||
* ...
|
||||
* </application>
|
||||
*</manifest></pre>
|
||||
*/
|
||||
abstract class NativePluginProvider : ContentProvider() {
|
||||
override fun getType(uri: Uri): String? = "application/x-elf"
|
||||
|
||||
override fun onCreate(): Boolean = true
|
||||
|
||||
/**
|
||||
* Provide all files needed for native plugin.
|
||||
*
|
||||
* @param provider A helper object to use to add files.
|
||||
*/
|
||||
protected abstract fun populateFiles(provider: PathProvider)
|
||||
|
||||
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?,
|
||||
sortOrder: String?): Cursor? {
|
||||
check(selection == null && selectionArgs == null && sortOrder == null)
|
||||
val result = MatrixCursor(projection)
|
||||
populateFiles(PathProvider(uri, result))
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns executable entry absolute path.
|
||||
* This is used for fast mode initialization where ss-local launches your native binary at the path given directly.
|
||||
* In order for this to work, plugin app is encouraged to have the following in its AndroidManifest.xml:
|
||||
* - android:installLocation="internalOnly" for <manifest>
|
||||
* - android:extractNativeLibs="true" for <application>
|
||||
*
|
||||
* Default behavior is throwing UnsupportedOperationException. If you don't wish to use this feature, use the
|
||||
* default behavior.
|
||||
*
|
||||
* @return Absolute path for executable entry.
|
||||
*/
|
||||
open fun getExecutable(): String = throw UnsupportedOperationException()
|
||||
|
||||
abstract fun openFile(uri: Uri): ParcelFileDescriptor
|
||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor {
|
||||
check(mode == "r")
|
||||
return openFile(uri)
|
||||
}
|
||||
|
||||
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? = when (method) {
|
||||
PluginContract.METHOD_GET_EXECUTABLE -> bundleOf(Pair(PluginContract.EXTRA_ENTRY, getExecutable()))
|
||||
else -> super.call(method, arg, extras)
|
||||
}
|
||||
|
||||
// Methods that should not be used
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? = throw UnsupportedOperationException()
|
||||
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int =
|
||||
throw UnsupportedOperationException()
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
/**
|
||||
* Activity that's capable of getting EXTRA_OPTIONS input.
|
||||
*/
|
||||
abstract class OptionsCapableActivity : AppCompatActivity() {
|
||||
protected fun pluginOptions(intent: Intent = this.intent) = try {
|
||||
PluginOptions("", intent.getStringExtra(PluginContract.EXTRA_OPTIONS))
|
||||
} catch (exc: IllegalArgumentException) {
|
||||
Toast.makeText(this, exc.message, Toast.LENGTH_SHORT).show()
|
||||
PluginOptions()
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate args to your user interface.
|
||||
*
|
||||
* @param options PluginOptions parsed.
|
||||
*/
|
||||
protected abstract fun onInitializePluginOptions(options: PluginOptions = pluginOptions())
|
||||
|
||||
override fun onPostCreate(savedInstanceState: Bundle?) {
|
||||
super.onPostCreate(savedInstanceState)
|
||||
if (savedInstanceState == null) onInitializePluginOptions()
|
||||
}
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Helper class to provide relative paths of files to copy.
|
||||
*/
|
||||
class PathProvider internal constructor(baseUri: Uri, private val cursor: MatrixCursor) {
|
||||
private val basePath = baseUri.path?.trim('/') ?: ""
|
||||
|
||||
fun addPath(path: String, mode: Int = 0b110100100): PathProvider {
|
||||
val trimmed = path.trim('/')
|
||||
if (trimmed.startsWith(basePath)) cursor.newRow()
|
||||
.add(PluginContract.COLUMN_PATH, trimmed)
|
||||
.add(PluginContract.COLUMN_MODE, mode)
|
||||
return this
|
||||
}
|
||||
fun addTo(file: File, to: String = "", mode: Int = 0b110100100): PathProvider {
|
||||
var sub = to + file.name
|
||||
if (basePath.startsWith(sub)) if (file.isDirectory) {
|
||||
sub += '/'
|
||||
file.listFiles()!!.forEach { addTo(it, sub, mode) }
|
||||
} else addPath(sub, mode)
|
||||
return this
|
||||
}
|
||||
fun addAt(file: File, at: String = "", mode: Int = 0b110100100): PathProvider {
|
||||
if (basePath.startsWith(at)) {
|
||||
if (file.isDirectory) file.listFiles()!!.forEach { addTo(it, at, mode) } else addPath(at, mode)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
/**
|
||||
* The contract between the plugin provider and host. Contains definitions for the supported actions, extras, etc.
|
||||
*
|
||||
* This class is written in Java to keep Java interoperability.
|
||||
*/
|
||||
object PluginContract {
|
||||
/**
|
||||
* ContentProvider Action: Used for NativePluginProvider.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"
|
||||
*/
|
||||
const val ACTION_NATIVE_PLUGIN = "com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"
|
||||
|
||||
/**
|
||||
* Activity Action: Used for ConfigurationActivity.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.ACTION_CONFIGURE"
|
||||
*/
|
||||
const val ACTION_CONFIGURE = "com.github.shadowsocks.plugin.ACTION_CONFIGURE"
|
||||
/**
|
||||
* Activity Action: Used for HelpActivity or HelpCallback.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.ACTION_HELP"
|
||||
*/
|
||||
const val ACTION_HELP = "com.github.shadowsocks.plugin.ACTION_HELP"
|
||||
|
||||
/**
|
||||
* The lookup key for a string that provides the plugin entry binary.
|
||||
*
|
||||
* Example: "/data/data/com.github.shadowsocks.plugin.obfs_local/lib/libobfs-local.so"
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.EXTRA_ENTRY"
|
||||
*/
|
||||
const val EXTRA_ENTRY = "com.github.shadowsocks.plugin.EXTRA_ENTRY"
|
||||
/**
|
||||
* The lookup key for a string that provides the options as a string.
|
||||
*
|
||||
* Example: "obfs=http;obfs-host=www.baidu.com"
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.EXTRA_OPTIONS"
|
||||
*/
|
||||
const val EXTRA_OPTIONS = "com.github.shadowsocks.plugin.EXTRA_OPTIONS"
|
||||
/**
|
||||
* The lookup key for a CharSequence that provides user relevant help message.
|
||||
*
|
||||
* Example: "obfs=<http></http>|tls> Enable obfuscating: HTTP or TLS (Experimental).
|
||||
* obfs-host=<host_name> Hostname for obfuscating (Experimental)."
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE"
|
||||
</host_name> */
|
||||
const val EXTRA_HELP_MESSAGE = "com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE"
|
||||
|
||||
/**
|
||||
* The metadata key to retrieve plugin version. Required for plugin applications.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.version"
|
||||
*/
|
||||
const val METADATA_KEY_VERSION = "com.github.shadowsocks.plugin.version"
|
||||
|
||||
/**
|
||||
* The metadata key to retrieve plugin id. Required for plugins.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.id"
|
||||
*/
|
||||
const val METADATA_KEY_ID = "com.github.shadowsocks.plugin.id"
|
||||
/**
|
||||
* The metadata key to retrieve plugin id aliases.
|
||||
* Can be a string (representing one alias) or a resource to a string or string array.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.id.aliases"
|
||||
*/
|
||||
const val METADATA_KEY_ID_ALIASES = "com.github.shadowsocks.plugin.id.aliases"
|
||||
/**
|
||||
* The metadata key to retrieve default configuration. Default value is empty.
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.default_config"
|
||||
*/
|
||||
const val METADATA_KEY_DEFAULT_CONFIG = "com.github.shadowsocks.plugin.default_config"
|
||||
/**
|
||||
* The metadata key to retrieve executable path to your native binary.
|
||||
* This path should be relative to your application's nativeLibraryDir.
|
||||
*
|
||||
* If this is set, the host app will prefer this value and (probably) not launch your app at all (aka faster mode).
|
||||
* In order for this to work, plugin app is encouraged to have the following in its AndroidManifest.xml:
|
||||
* - android:installLocation="internalOnly" for <manifest>
|
||||
* - android:extractNativeLibs="true" for <application>
|
||||
*
|
||||
* Do not use this if you plan to do some setup work before giving away your binary path,
|
||||
* or your native binary is not at a fixed location relative to your application's nativeLibraryDir.
|
||||
*
|
||||
* Since plugin lib: 1.3.0
|
||||
*
|
||||
* Constant Value: "com.github.shadowsocks.plugin.executable_path"
|
||||
*/
|
||||
const val METADATA_KEY_EXECUTABLE_PATH = "com.github.shadowsocks.plugin.executable_path"
|
||||
|
||||
const val METHOD_GET_EXECUTABLE = "shadowsocks:getExecutable"
|
||||
|
||||
/** ConfigurationActivity result: fallback to manual edit mode. */
|
||||
const val RESULT_FALLBACK = 1
|
||||
|
||||
/**
|
||||
* Relative to the file to be copied. This column is required.
|
||||
*
|
||||
* Example: "kcptun", "doc/help.txt"
|
||||
*
|
||||
* Type: String
|
||||
*/
|
||||
const val COLUMN_PATH = "path"
|
||||
/**
|
||||
* File mode bits. Default value is 644 in octal.
|
||||
*
|
||||
* Example: 0b110100100 (for 755 in octal)
|
||||
*
|
||||
* Type: Int or String (deprecated)
|
||||
*/
|
||||
const val COLUMN_MODE = "mode"
|
||||
|
||||
/**
|
||||
* The scheme for general plugin actions.
|
||||
*/
|
||||
const val SCHEME = "plugin"
|
||||
/**
|
||||
* The authority for general plugin actions.
|
||||
*/
|
||||
const val AUTHORITY = "com.github.shadowsocks"
|
||||
}
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Helper class for processing plugin options.
|
||||
*
|
||||
* Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java
|
||||
*/
|
||||
class PluginOptions : HashMap<String, String?> {
|
||||
var id = ""
|
||||
|
||||
constructor() : super()
|
||||
constructor(initialCapacity: Int) : super(initialCapacity)
|
||||
constructor(initialCapacity: Int, loadFactor: Float) : super(initialCapacity, loadFactor)
|
||||
|
||||
private constructor(options: String?, parseId: Boolean) : this() {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var parseId = parseId
|
||||
if (options.isNullOrEmpty()) return
|
||||
check(options.all { !it.isISOControl() }) { "No control characters allowed." }
|
||||
val tokenizer = StringTokenizer("$options;", "\\=;", true)
|
||||
val current = StringBuilder()
|
||||
var key: String? = null
|
||||
while (tokenizer.hasMoreTokens()) when (val nextToken = tokenizer.nextToken()) {
|
||||
"\\" -> current.append(tokenizer.nextToken())
|
||||
"=" -> if (key == null) {
|
||||
key = current.toString()
|
||||
current.setLength(0)
|
||||
} else current.append(nextToken)
|
||||
";" -> {
|
||||
if (key != null) {
|
||||
put(key, current.toString())
|
||||
key = null
|
||||
} else if (current.isNotEmpty()) {
|
||||
if (parseId) id = current.toString() else put(current.toString(), null)
|
||||
}
|
||||
current.setLength(0)
|
||||
parseId = false
|
||||
}
|
||||
else -> current.append(nextToken)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(options: String?) : this(options, true)
|
||||
constructor(id: String, options: String?) : this(options, false) {
|
||||
this.id = id
|
||||
}
|
||||
|
||||
/**
|
||||
* Put but if value is null or default, the entry is deleted.
|
||||
*
|
||||
* @return Old value before put.
|
||||
*/
|
||||
fun putWithDefault(key: String, value: String?, default: String? = null) =
|
||||
if (value == null || value == default) remove(key) else put(key, value)
|
||||
|
||||
private fun append(result: StringBuilder, str: String) = str.indices.map { str[it] }.forEach {
|
||||
when (it) {
|
||||
'\\', '=', ';' -> {
|
||||
result.append('\\') // intentionally no break
|
||||
result.append(it)
|
||||
}
|
||||
else -> result.append(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun toString(trimId: Boolean): String {
|
||||
val result = StringBuilder()
|
||||
if (!trimId) if (id.isEmpty()) return "" else append(result, id)
|
||||
for ((key, value) in entries) {
|
||||
if (result.isNotEmpty()) result.append(';')
|
||||
append(result, key)
|
||||
if (value != null) {
|
||||
result.append('=')
|
||||
append(result, value)
|
||||
}
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
override fun toString(): String = toString(true)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
return javaClass == other?.javaClass && super.equals(other) && id == (other as PluginOptions).id
|
||||
}
|
||||
override fun hashCode(): Int = Objects.hash(super.hashCode(), id)
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2020 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2020 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
@file:JvmName("Utils")
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class Empty : Parcelable
|
||||
|
||||
@JvmOverloads
|
||||
@Deprecated("Moved to fragment package", ReplaceWith("fragment.showAllowingStateLoss"))
|
||||
fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String? = null) {
|
||||
if (!fragmentManager.isStateSaved) show(fragmentManager, tag)
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2020 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2020 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
/**
|
||||
* Based on: https://android.googlesource.com/platform/packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java
|
||||
*/
|
||||
abstract class AlertDialogFragment<Arg : Parcelable, Ret : Parcelable?> :
|
||||
AppCompatDialogFragment(), DialogInterface.OnClickListener {
|
||||
companion object {
|
||||
private const val KEY_RESULT = "result"
|
||||
private const val KEY_ARG = "arg"
|
||||
private const val KEY_RET = "ret"
|
||||
private const val KEY_WHICH = "which"
|
||||
|
||||
fun <Ret : Parcelable> setResultListener(fragment: Fragment, requestKey: String,
|
||||
listener: (Int, Ret?) -> Unit) {
|
||||
fragment.setFragmentResultListener(requestKey) { _, bundle ->
|
||||
listener(bundle.getInt(KEY_WHICH, Activity.RESULT_CANCELED), bundle.getParcelable(KEY_RET))
|
||||
}
|
||||
}
|
||||
inline fun <reified T : AlertDialogFragment<*, Ret>, Ret : Parcelable?> setResultListener(
|
||||
fragment: Fragment, noinline listener: (Int, Ret?) -> Unit) =
|
||||
setResultListener(fragment, T::class.java.name, listener)
|
||||
}
|
||||
protected abstract fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener)
|
||||
|
||||
private val resultKey get() = requireArguments().getString(KEY_RESULT)
|
||||
protected val arg by lazy { requireArguments().getParcelable<Arg>(KEY_ARG)!! }
|
||||
protected open fun ret(which: Int): Ret? = null
|
||||
|
||||
private fun args() = arguments ?: Bundle().also { arguments = it }
|
||||
fun arg(arg: Arg) = args().putParcelable(KEY_ARG, arg)
|
||||
fun key(resultKey: String = javaClass.name) = args().putString(KEY_RESULT, resultKey)
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog =
|
||||
MaterialAlertDialogBuilder(requireContext()).also { it.prepare(this) }.create()
|
||||
|
||||
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||
setFragmentResult(resultKey ?: return, Bundle().apply {
|
||||
putInt(KEY_WHICH, which)
|
||||
putParcelable(KEY_RET, ret(which) ?: return@apply)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
onClick(null, Activity.RESULT_CANCELED)
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2020 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2020 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
@file:JvmName("Utils")
|
||||
|
||||
package com.github.shadowsocks.plugin.fragment
|
||||
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
|
||||
typealias Empty = com.github.shadowsocks.plugin.Empty
|
||||
|
||||
@JvmOverloads
|
||||
fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String? = null) {
|
||||
if (!fragmentManager.isStateSaved) show(fragmentManager, tag)
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Source: https://github.com/material-components/material-components-android/blob/2de39fafe0285aab7e6e101549c4bc93f184a7e5/lib/java/com/google/android/material/button/res/color/mtrl_text_btn_text_color_selector.xml
|
||||
Copyright 2017 The Android Open Source Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:alpha="1.00" android:color="@color/color_primary_text" android:state_checkable="true" android:state_checked="true" android:state_enabled="true"/>
|
||||
<item android:alpha="0.60" android:color="?attr/colorOnSurface" android:state_checkable="true" android:state_checked="false" android:state_enabled="true"/>
|
||||
<item android:alpha="1.00" android:color="@color/color_primary_text" android:state_enabled="true"/>
|
||||
<item android:alpha="0.38" android:color="?attr/colorOnSurface"/>
|
||||
</selector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:elevation="4dp"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.DayNight"
|
||||
android:id="@+id/toolbar" />
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"Servereinstellungen"</string>
|
||||
<string name="feature_cat">"Funktionseinstellungen"</string>
|
||||
<string name="unsaved_changes_prompt">"Änderungen nicht gespeichert. Speichern?"</string>
|
||||
<string name="yes">"Ja"</string>
|
||||
<string name="no">"Nein"</string>
|
||||
<string name="apply">"Anwenden"</string>
|
||||
<string name="file_manager_missing">"Bitte installiere einen Dateimanager, z.B. MiXplorer"</string>
|
||||
<string name="browse">"Durchsuchen..."</string>
|
||||
</resources>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"Propiedades del Servidor"</string>
|
||||
<string name="yes">"Sí"</string>
|
||||
<string name="no">"No"</string>
|
||||
<string name="apply">"Aplicar"</string>
|
||||
<string name="file_manager_missing">"Por favor, instala un explorador de archivos como MiXplorer"</string>
|
||||
</resources>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"تنظیمات سرور"</string>
|
||||
<string name="feature_cat">"تنظیمات ویژگیها"</string>
|
||||
<string name="unsaved_changes_prompt">"تغییرات ذخیره نشدهاند. ذخیره شوند؟"</string>
|
||||
<string name="yes">"بله"</string>
|
||||
<string name="no">"خیر"</string>
|
||||
<string name="apply">"تایید"</string>
|
||||
<string name="file_manager_missing">"لطفاً یک فایل منیجر مانند MiXplorer نصب کنید"</string>
|
||||
<string name="browse">"مرور کردن..."</string>
|
||||
</resources>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"Paramètres du Serveur"</string>
|
||||
<string name="feature_cat">"Paramètres des Fonctionnalités"</string>
|
||||
<string name="unsaved_changes_prompt">"Changements non enregistrés. Voulez-vous enregistrer ?"</string>
|
||||
<string name="yes">"Oui"</string>
|
||||
<string name="no">"Non"</string>
|
||||
<string name="apply">"Appliquer"</string>
|
||||
<string name="file_manager_missing">"Veuillez installer un gestionnaire de fichier tel que MiXplorer"</string>
|
||||
</resources>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"サーバー設定"</string>
|
||||
<string name="feature_cat">"機能設定"</string>
|
||||
<string name="unsaved_changes_prompt">"変更は保存されておりません、保存しますか?"</string>
|
||||
<string name="yes">"はい"</string>
|
||||
<string name="no">"いいえ"</string>
|
||||
<string name="apply">"適応"</string>
|
||||
<string name="file_manager_missing">"ファイルマネージャーをインストールしてください(MiXplorerなど)"</string>
|
||||
<string name="browse">"参照…"</string>
|
||||
</resources>
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"서버 설정"</string>
|
||||
<string name="feature_cat">"기능 설정"</string>
|
||||
<string name="unsaved_changes_prompt">"변경 사항이 저장되지 않았습니다. 저장하시겠습니까?"</string>
|
||||
<string name="yes">"예"</string>
|
||||
<string name="no">"아니오"</string>
|
||||
<string name="apply">"적용"</string>
|
||||
</resources>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="color_primary">@color/dark_color_primary</color>
|
||||
<color name="color_primary_dark">@color/dark_color_primary_dark</color>
|
||||
<color name="color_primary_text">@color/dark_color_primary_text</color>
|
||||
</resources>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"Настройки сервера"</string>
|
||||
<string name="feature_cat">"Функции"</string>
|
||||
<string name="unsaved_changes_prompt">"Сохранить изменения?"</string>
|
||||
<string name="yes">"Да"</string>
|
||||
<string name="no">"Нет"</string>
|
||||
<string name="apply">"Применить"</string>
|
||||
<string name="file_manager_missing">"Установите файловый менеджер (например, MiXplorer)"</string>
|
||||
<string name="browse">"Открыть…"</string>
|
||||
</resources>
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"Sunucu Ayarları"</string>
|
||||
<string name="feature_cat">"Özellik Ayarları"</string>
|
||||
<string name="unsaved_changes_prompt">"Değişiklikler kaydedilmedi. Kaydetmek ister misiniz?"</string>
|
||||
<string name="yes">"Evet"</string>
|
||||
<string name="no">"Hayır"</string>
|
||||
<string name="apply">"Uygula"</string>
|
||||
</resources>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"Налаштування сервера"</string>
|
||||
<string name="feature_cat">"Налаштування функцій"</string>
|
||||
<string name="unsaved_changes_prompt">"Зміни не збережено. Зберегти?"</string>
|
||||
<string name="yes">"Так"</string>
|
||||
<string name="no">"Ні"</string>
|
||||
<string name="apply">"Застосувати"</string>
|
||||
<string name="file_manager_missing">"Будь ласка, встановіть менеджер файлів, наприклад, MiXplorer"</string>
|
||||
</resources>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.Shadowsocks.Immersive">
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"服务器设置"</string>
|
||||
<string name="feature_cat">"功能设置"</string>
|
||||
<string name="unsaved_changes_prompt">"是否要保存修改?"</string>
|
||||
<string name="yes">"是"</string>
|
||||
<string name="no">"否"</string>
|
||||
<string name="apply">"应用"</string>
|
||||
<string name="file_manager_missing">"请安装文件管理器,如 MiXplorer"</string>
|
||||
<string name="browse">"浏览…"</string>
|
||||
</resources>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com>
|
||||
Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DO NOT EDIT: This file was automagically generated by script.
|
||||
If you are looking for contributing a translation, read this:
|
||||
https://discourse.shadowsocks.org/t/poeditor-translation-main-thread/30
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="proxy_cat">"伺服器設定"</string>
|
||||
<string name="feature_cat">"功能設定"</string>
|
||||
<string name="unsaved_changes_prompt">"要儲存變更嗎?"</string>
|
||||
<string name="yes">"是"</string>
|
||||
<string name="no">"否"</string>
|
||||
<string name="apply">"套用"</string>
|
||||
<string name="file_manager_missing">"請安裝文件管理器,如 MiXplorer"</string>
|
||||
<string name="browse">"瀏覽…"</string>
|
||||
</resources>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
|
||||
<color name="material_green_700">#388E3C</color>
|
||||
<color name="material_green_a700">#00C853</color>
|
||||
<color name="material_blue_grey_100">#CFD8DC</color>
|
||||
<color name="material_blue_grey_300">#90A4AE</color>
|
||||
<color name="material_blue_grey_500">#607D8B</color>
|
||||
<color name="material_blue_grey_600">#546E7A</color>
|
||||
<color name="material_blue_grey_700">#455A64</color>
|
||||
<color name="material_primary_100">@color/material_blue_grey_100</color>
|
||||
<color name="material_primary_300">@color/material_blue_grey_300</color>
|
||||
<color name="material_primary_500">@color/material_blue_grey_500</color>
|
||||
<color name="material_primary_600">@color/material_blue_grey_600</color>
|
||||
<color name="material_primary_700">@color/material_blue_grey_700</color>
|
||||
<color name="material_primary_800">@color/material_blue_grey_800</color>
|
||||
<color name="material_primary_900">@color/material_blue_grey_900</color>
|
||||
<color name="material_accent_200">@color/material_green_a700</color>
|
||||
|
||||
<color name="light_color_primary">@color/material_primary_500</color>
|
||||
<color name="light_color_primary_dark">@color/material_primary_700</color>
|
||||
<color name="light_color_primary_text">@color/material_primary_500</color>
|
||||
<color name="dark_color_primary">@color/material_primary_800</color>
|
||||
<color name="dark_color_primary_dark">@color/material_primary_900</color>
|
||||
<color name="dark_color_primary_text">@color/material_primary_300</color>
|
||||
|
||||
<color name="color_primary">@color/light_color_primary</color>
|
||||
<color name="color_primary_dark">@color/light_color_primary_dark</color>
|
||||
<color name="color_primary_text">@color/light_color_primary_text</color>
|
||||
|
||||
</resources>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="proxy_cat">Server Settings</string>
|
||||
<string name="feature_cat">Feature Settings</string>
|
||||
<string name="unsaved_changes_prompt">Changes not saved. Do you want to save?</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="apply">Apply</string>
|
||||
<string name="browse">Browse…</string>
|
||||
<string name="file_manager_missing">Please install a file manager like MiXplorer</string>
|
||||
</resources>
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.Shadowsocks" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="android:navigationBarColor">@color/color_primary_dark</item>
|
||||
<item name="actionBarStyle">@style/Widget.MaterialComponents.Light.ActionBar.Solid</item>
|
||||
<item name="actionModeCloseDrawable">@drawable/ic_navigation_close</item>
|
||||
<item name="colorAccent">@color/material_accent_200</item>
|
||||
<item name="colorButtonNormal">@color/material_accent_200</item>
|
||||
<item name="colorPrimary">@color/color_primary</item>
|
||||
<item name="colorPrimaryDark">@color/color_primary_dark</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
|
||||
<!-- Remove ActionBar but keep styles and themes -->
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
<style name="Theme.Shadowsocks.ActionBar">
|
||||
<item name="windowActionBar">true</item>
|
||||
<item name="windowNoTitle">false</item>
|
||||
</style>
|
||||
<style name="Theme.Shadowsocks.Immersive">
|
||||
<item name="android:navigationBarColor">#6000</item>
|
||||
</style>
|
||||
<style name="Theme.Shadowsocks.Translucent" parent="Theme.MaterialComponents.Dialog">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowCloseOnTouchOutside">false</item>
|
||||
<item name="colorAccent">@color/material_accent_200</item>
|
||||
<item name="colorButtonNormal">@color/material_accent_200</item>
|
||||
<item name="colorPrimary">@color/color_primary</item>
|
||||
<item name="colorPrimaryDark">@color/color_primary_dark</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
<style name="Theme.AppCompat.Translucent" parent="Theme.AppCompat.Dialog">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowCloseOnTouchOutside">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.plugin
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class PluginOptionsTest {
|
||||
@Test
|
||||
fun basic() {
|
||||
val o1 = PluginOptions("obfs-local;obfs=http;obfs-host=localhost")
|
||||
val o2 = PluginOptions("obfs-local", "obfs-host=localhost;obfs=http")
|
||||
Assert.assertEquals(o1.hashCode(), o2.hashCode())
|
||||
Assert.assertEquals(true, o1 == o2)
|
||||
val o3 = PluginOptions(o1.toString(false))
|
||||
Assert.assertEquals(true, o2 == o3)
|
||||
val o4 = PluginOptions(o2.id, o2.toString())
|
||||
Assert.assertEquals(true, o3 == o4)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nullValues() {
|
||||
val o = PluginOptions("", "a;b;c;d=3")
|
||||
Assert.assertEquals(true, o == PluginOptions("", o.toString()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun escape() {
|
||||
val options = PluginOptions("escapeTest")
|
||||
options["subject"] = "value;semicolon"
|
||||
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
|
||||
options["key;semicolon"] = "object"
|
||||
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
|
||||
options["subject"] = "value=equals"
|
||||
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
|
||||
options["key=equals"] = "object"
|
||||
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
|
||||
options["advanced\\=;test"] = "in;=\\progress"
|
||||
Assert.assertEquals(true, options == PluginOptions(options.toString(false)))
|
||||
}
|
||||
}
|
||||
@@ -7,23 +7,12 @@
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28"/>
|
||||
|
||||
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" />
|
||||
</intent>
|
||||
</queries>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
|
||||
<application
|
||||
@@ -86,7 +75,6 @@
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
<!-- https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/work/workmanager/src/main/AndroidManifest.xml -->
|
||||
<provider
|
||||
@@ -140,18 +128,5 @@
|
||||
android:directBootAware="true"
|
||||
android:process=":QtOnlyProcess"
|
||||
tools:replace="android:directBootAware" />
|
||||
|
||||
<service android:name="com.google.firebase.components.ComponentDiscoveryService"
|
||||
android:process=":QtOnlyProcess"
|
||||
android:directBootAware="true"/>
|
||||
|
||||
<provider android:name="com.google.firebase.provider.FirebaseInitProvider"
|
||||
android:process=":QtOnlyProcess"
|
||||
tools:node="remove"/>
|
||||
|
||||
<service android:name="androidx.room.MultiInstanceInvalidationService"
|
||||
android:process=":bg"/>
|
||||
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
+9
-13
@@ -25,31 +25,27 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import org.amnezia.vpn.shadowsocks.core.Core.app
|
||||
import org.amnezia.vpn.shadowsocks.core.preference.DataStore
|
||||
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
companion object {
|
||||
private val componentName by lazy { ComponentName(app, BootReceiver::class.java) }
|
||||
private val componentName by lazy { ComponentName(app, org.amnezia.vpn.shadowsocks.core.BootReceiver::class.java) }
|
||||
var enabled: Boolean
|
||||
get() = app.packageManager.getComponentEnabledSetting(componentName) ==
|
||||
get() = app.packageManager.getComponentEnabledSetting(org.amnezia.vpn.shadowsocks.core.BootReceiver.Companion.componentName) ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
set(value) = app.packageManager.setComponentEnabledSetting(componentName,
|
||||
set(value) = app.packageManager.setComponentEnabledSetting(
|
||||
org.amnezia.vpn.shadowsocks.core.BootReceiver.Companion.componentName,
|
||||
if (value) PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
else PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (!DataStore.persistAcrossReboot) { // sanity check
|
||||
enabled = false
|
||||
return
|
||||
val locked = when (intent.action) {
|
||||
Intent.ACTION_BOOT_COMPLETED -> false
|
||||
Intent.ACTION_LOCKED_BOOT_COMPLETED -> true // constant will be folded so no need to do version checks
|
||||
else -> return
|
||||
}
|
||||
val doStart = when (intent.action) {
|
||||
Intent.ACTION_BOOT_COMPLETED -> !DataStore.directBootAware
|
||||
Intent.ACTION_LOCKED_BOOT_COMPLETED -> DataStore.directBootAware
|
||||
else -> DataStore.directBootAware || Build.VERSION.SDK_INT >= 24 && Core.user.isUserUnlocked
|
||||
}
|
||||
if (doStart) Core.startService()
|
||||
if (DataStore.directBootAware == locked) org.amnezia.vpn.shadowsocks.core.Core.startService()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,72 +20,60 @@
|
||||
|
||||
package org.amnezia.vpn.shadowsocks.core
|
||||
|
||||
import android.app.*
|
||||
import android.app.Application
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.*
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Build
|
||||
import android.os.UserManager
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.persistableBundleOf
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
|
||||
import org.amnezia.vpn.shadowsocks.core.acl.Acl
|
||||
import org.amnezia.vpn.shadowsocks.core.aidl.ShadowsocksConnection
|
||||
import org.amnezia.vpn.shadowsocks.core.BuildConfig
|
||||
import org.amnezia.vpn.shadowsocks.core.R
|
||||
import org.amnezia.vpn.shadowsocks.core.database.Profile
|
||||
import org.amnezia.vpn.shadowsocks.core.database.ProfileManager
|
||||
import org.amnezia.vpn.shadowsocks.core.net.TcpFastOpen
|
||||
import org.amnezia.vpn.shadowsocks.core.preference.DataStore
|
||||
import org.amnezia.vpn.shadowsocks.core.subscription.SubscriptionService
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.Action
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.DeviceStorageApp
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.DirectBoot
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.Key
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.google.firebase.ktx.initialize
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.*
|
||||
import kotlinx.coroutines.DEBUG_PROPERTY_NAME
|
||||
import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
object Core : Configuration.Provider {
|
||||
object Core {
|
||||
const val TAG = "Core"
|
||||
|
||||
lateinit var app: Application
|
||||
@VisibleForTesting set
|
||||
lateinit var configureIntent: (Context) -> PendingIntent
|
||||
val activity by lazy { app.getSystemService<ActivityManager>()!! }
|
||||
val clipboard by lazy { app.getSystemService<ClipboardManager>()!! }
|
||||
val connectivity by lazy { app.getSystemService<ConnectivityManager>()!! }
|
||||
val notification by lazy { app.getSystemService<NotificationManager>()!! }
|
||||
val user by lazy { app.getSystemService<UserManager>()!! }
|
||||
val packageInfo: PackageInfo by lazy { getPackageInfo(app.packageName) }
|
||||
val deviceStorage by lazy { if (Build.VERSION.SDK_INT < 24) app else DeviceStorageApp(app) }
|
||||
val directBootSupported by lazy {
|
||||
Build.VERSION.SDK_INT >= 24 && try {
|
||||
app.getSystemService<DevicePolicyManager>()?.storageEncryptionStatus ==
|
||||
DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER
|
||||
} catch (_: RuntimeException) {
|
||||
false
|
||||
}
|
||||
Build.VERSION.SDK_INT >= 24 && app.getSystemService<DevicePolicyManager>()?.storageEncryptionStatus ==
|
||||
DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER
|
||||
}
|
||||
|
||||
val activeProfileIds get() = ProfileManager.getProfile(DataStore.profileId).let {
|
||||
if (it == null) emptyList() else listOfNotNull(it.id, it.udpFallback)
|
||||
}
|
||||
val currentProfile: ProfileManager.ExpandedProfile? get() {
|
||||
if (DataStore.directBootAware) DirectBoot.getDeviceProfile()?.apply { return this }
|
||||
return ProfileManager.expand(ProfileManager.getProfile(DataStore.profileId) ?: return null)
|
||||
}
|
||||
val activeProfileIds
|
||||
get() = ProfileManager.getProfile(DataStore.profileId).let {
|
||||
if (it == null) emptyList() else listOfNotNull(it.id, it.udpFallback)
|
||||
}
|
||||
val currentProfile: Pair<Profile, Profile?>?
|
||||
get() {
|
||||
if (DataStore.directBootAware) DirectBoot.getDeviceProfile()?.apply { return this }
|
||||
return ProfileManager.expand(ProfileManager.getProfile(DataStore.profileId)
|
||||
?: return null)
|
||||
}
|
||||
|
||||
fun switchProfile(id: Long): Profile {
|
||||
val result = ProfileManager.getProfile(id) ?: ProfileManager.createProfile()
|
||||
@@ -94,93 +82,78 @@ object Core : Configuration.Provider {
|
||||
}
|
||||
|
||||
fun init(app: Application, configureClass: KClass<out Any>) {
|
||||
this.app = app
|
||||
this.configureIntent = {
|
||||
PendingIntent.getActivity(it, 0, Intent(it, configureClass.java)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), PendingIntent.FLAG_IMMUTABLE)
|
||||
Core.app = app
|
||||
configureIntent = {
|
||||
PendingIntent.getActivity(it, 0,
|
||||
Intent(it, configureClass.java).setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
|
||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) { // migrate old files
|
||||
deviceStorage.moveDatabaseFrom(app, Key.DB_PUBLIC)
|
||||
val old = Acl.getFile(Acl.CUSTOM_RULES_USER, app)
|
||||
val old = Acl.getFile(Acl.CUSTOM_RULES, app)
|
||||
if (old.canRead()) {
|
||||
Acl.getFile(Acl.CUSTOM_RULES_USER).writeText(old.readText())
|
||||
Acl.getFile(Acl.CUSTOM_RULES).writeText(old.readText())
|
||||
old.delete()
|
||||
}
|
||||
}
|
||||
|
||||
// overhead of debug mode is minimal: https://github.com/Kotlin/kotlinx.coroutines/blob/f528898/docs/debugging.md#debug-mode
|
||||
System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
|
||||
/* Firebase.initialize(deviceStorage) // multiple processes needs manual set-up
|
||||
Timber.plant(object : Timber.DebugTree() {
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
if (t == null) {
|
||||
if (priority != Log.DEBUG || BuildConfig.DEBUG) Log.println(priority, tag, message)
|
||||
FirebaseCrashlytics.getInstance().log("${"XXVDIWEF".getOrElse(priority) { 'X' }}/$tag: $message")
|
||||
} else {
|
||||
if (priority >= Log.WARN || priority == Log.DEBUG) Log.println(priority, tag, message)
|
||||
if (priority >= Log.INFO) FirebaseCrashlytics.getInstance().recordException(t)
|
||||
}
|
||||
}
|
||||
})*/
|
||||
|
||||
// handle data restored/crash
|
||||
if (Build.VERSION.SDK_INT >= 24 && DataStore.directBootAware && user.isUserUnlocked) {
|
||||
DirectBoot.flushTrafficStats()
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 24 && DataStore.directBootAware &&
|
||||
app.getSystemService<UserManager>()?.isUserUnlocked == true) DirectBoot.flushTrafficStats()
|
||||
if (DataStore.tcpFastOpen && !TcpFastOpen.sendEnabled) TcpFastOpen.enableTimeout()
|
||||
if (DataStore.publicStore.getLong(Key.assetUpdateTime, -1) != packageInfo.lastUpdateTime) {
|
||||
val assetManager = app.assets
|
||||
try {
|
||||
for (file in assetManager.list("acl")!!) assetManager.open("acl/$file").use { input ->
|
||||
File(deviceStorage.noBackupFilesDir, file).outputStream().use { output -> input.copyTo(output) }
|
||||
File(ContextCompat.getNoBackupFilesDir(deviceStorage), file).outputStream().use { output -> input.copyTo(output) }
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.w(e)
|
||||
printLog(e)
|
||||
}
|
||||
DataStore.publicStore.putLong(Key.assetUpdateTime, packageInfo.lastUpdateTime)
|
||||
}
|
||||
updateNotificationChannels()
|
||||
}
|
||||
|
||||
override fun getWorkManagerConfiguration() = Configuration.Builder().apply {
|
||||
setDefaultProcessName(app.packageName + ":bg")
|
||||
setMinimumLoggingLevel(if (BuildConfig.DEBUG) Log.VERBOSE else Log.INFO)
|
||||
setExecutor { GlobalScope.launch { it.run() } }
|
||||
setTaskExecutor { GlobalScope.launch { it.run() } }
|
||||
}.build()
|
||||
|
||||
fun updateNotificationChannels() {
|
||||
/* if (Build.VERSION.SDK_INT >= 26) @RequiresApi(26) {
|
||||
notification.createNotificationChannels(listOf(
|
||||
if (Build.VERSION.SDK_INT >= 26) @RequiresApi(26) {
|
||||
val nm = app.getSystemService<NotificationManager>()!!
|
||||
nm.createNotificationChannels(listOf(
|
||||
NotificationChannel("service-vpn", app.getText(R.string.service_vpn),
|
||||
if (Build.VERSION.SDK_INT >= 28) NotificationManager.IMPORTANCE_MIN
|
||||
else NotificationManager.IMPORTANCE_LOW), // #1355
|
||||
NotificationManager.IMPORTANCE_LOW),
|
||||
NotificationChannel("service-proxy", app.getText(R.string.service_proxy),
|
||||
NotificationManager.IMPORTANCE_LOW),
|
||||
NotificationChannel("service-transproxy", app.getText(R.string.service_transproxy),
|
||||
NotificationManager.IMPORTANCE_LOW),
|
||||
SubscriptionService.notificationChannel))
|
||||
notification.deleteNotificationChannel("service-nat") // NAT mode is gone for good
|
||||
} */
|
||||
NotificationManager.IMPORTANCE_LOW)))
|
||||
nm.deleteNotificationChannel("service-nat") // NAT mode is gone for good
|
||||
}
|
||||
}
|
||||
|
||||
fun getPackageInfo(packageName: String) = app.packageManager.getPackageInfo(packageName,
|
||||
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES
|
||||
else @Suppress("DEPRECATION") PackageManager.GET_SIGNATURES)!!
|
||||
|
||||
fun trySetPrimaryClip(clip: String, isSensitive: Boolean = false) = try {
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(null, clip).apply {
|
||||
if (isSensitive && Build.VERSION.SDK_INT >= 24) {
|
||||
//description.extras = persistableBundleOf(ClipDescription.EXTRA_IS_SENSITIVE to true)
|
||||
}
|
||||
})
|
||||
true
|
||||
} catch (e: RuntimeException) {
|
||||
Timber.d(e)
|
||||
false
|
||||
}
|
||||
|
||||
fun startService() = ContextCompat.startForegroundService(app, Intent(app, ShadowsocksConnection.serviceClass))
|
||||
fun reloadService() = app.sendBroadcast(Intent(Action.RELOAD).setPackage(app.packageName))
|
||||
fun stopService() = app.sendBroadcast(Intent(Action.CLOSE).setPackage(app.packageName))
|
||||
fun reloadService() = app.sendBroadcast(Intent(Action.RELOAD))
|
||||
fun stopService() = app.sendBroadcast(Intent(Action.CLOSE))
|
||||
|
||||
fun listenForPackageChanges(onetime: Boolean = true, callback: () -> Unit) = object : BroadcastReceiver() {
|
||||
init {
|
||||
app.registerReceiver(this, IntentFilter().apply {
|
||||
addAction(Intent.ACTION_PACKAGE_ADDED)
|
||||
addAction(Intent.ACTION_PACKAGE_REMOVED)
|
||||
addDataScheme("package")
|
||||
})
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) return
|
||||
callback()
|
||||
if (onetime) app.unregisterReceiver(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2019 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package org.amnezia.vpn.shadowsocks.core
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.amnezia.vpn.shadowsocks.core.R
|
||||
import org.amnezia.vpn.shadowsocks.core.database.Profile
|
||||
import org.amnezia.vpn.shadowsocks.core.database.ProfileManager
|
||||
import org.amnezia.vpn.shadowsocks.plugin.fragment.AlertDialogFragment
|
||||
import org.amnezia.vpn.shadowsocks.plugin.fragment.Empty
|
||||
import org.amnezia.vpn.shadowsocks.plugin.fragment.showAllowingStateLoss
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
class UrlImportActivity : AppCompatActivity() {
|
||||
@Parcelize
|
||||
data class ProfilesArg(val profiles: List<Profile>) : Parcelable
|
||||
class ImportProfilesDialogFragment : AlertDialogFragment<ProfilesArg, Empty>() {
|
||||
override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) {
|
||||
setTitle(R.string.add_profile_dialog)
|
||||
setPositiveButton(R.string.yes, listener)
|
||||
setNegativeButton(R.string.no, listener)
|
||||
setMessage(arg.profiles.joinToString("\n"))
|
||||
}
|
||||
|
||||
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) arg.profiles.forEach { ProfileManager.createProfile(it) }
|
||||
requireActivity().finish()
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
requireActivity().finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
when (val dialog = handleShareIntent()) {
|
||||
null -> {
|
||||
Toast.makeText(this, R.string.profile_invalid_input, Toast.LENGTH_SHORT).show()
|
||||
finish()
|
||||
}
|
||||
else -> dialog.showAllowingStateLoss(supportFragmentManager)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleShareIntent() = intent.data?.toString()?.let { sharedStr ->
|
||||
val profiles = Profile.findAllUrls(sharedStr, Core.currentProfile?.main).toList()
|
||||
if (profiles.isEmpty()) null else ImportProfilesDialogFragment().apply {
|
||||
arg(ProfilesArg(profiles))
|
||||
key()
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -18,7 +18,8 @@ class VpnManager private constructor() {
|
||||
|
||||
var state = BaseService.State.Idle
|
||||
private var context: Context? = null
|
||||
private val connection = ShadowsocksConnection(true)
|
||||
private val handler = Handler()
|
||||
private val connection = ShadowsocksConnection(handler, true)
|
||||
private var listener: OnStatusChangeListener? = null
|
||||
private val callback: ShadowsocksConnection.Callback = object : ShadowsocksConnection.Callback {
|
||||
override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) {
|
||||
@@ -68,7 +69,7 @@ class VpnManager private constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
fun init(context: Context){
|
||||
this.context=context
|
||||
connect()
|
||||
}
|
||||
|
||||
+19
-6
@@ -24,17 +24,22 @@ import android.app.KeyguardManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.VpnService
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.getSystemService
|
||||
import org.amnezia.vpn.shadowsocks.core.R
|
||||
|
||||
import org.amnezia.vpn.shadowsocks.core.preference.DataStore
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.Key
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.StartService
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.broadcastReceiver
|
||||
|
||||
class VpnRequestActivity : AppCompatActivity() {
|
||||
companion object {
|
||||
private const val TAG = "VpnRequestActivity"
|
||||
private const val REQUEST_CONNECT = 1
|
||||
}
|
||||
|
||||
private var receiver: BroadcastReceiver? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -44,13 +49,21 @@ class VpnRequestActivity : AppCompatActivity() {
|
||||
return
|
||||
}
|
||||
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {
|
||||
receiver = broadcastReceiver { _, _ -> connect.launch(null) }
|
||||
receiver = broadcastReceiver { _, _ -> request() }
|
||||
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
|
||||
} else connect.launch(null)
|
||||
} else request()
|
||||
}
|
||||
|
||||
private val connect = registerForActivityResult(StartService()) {
|
||||
if (it) Toast.makeText(this, R.string.vpn_permission_denied, Toast.LENGTH_LONG).show()
|
||||
private fun request() {
|
||||
val intent = VpnService.prepare(this)
|
||||
if (intent == null) onActivityResult(REQUEST_CONNECT, RESULT_OK, null)
|
||||
else startActivityForResult(intent, REQUEST_CONNECT)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == RESULT_OK) Core.startService() else {
|
||||
Toast.makeText(this, R.string.vpn_permission_denied, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
|
||||
+64
-84
@@ -1,46 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package org.amnezia.vpn.shadowsocks.core.acl
|
||||
|
||||
import android.content.Context
|
||||
import androidx.recyclerview.widget.SortedList
|
||||
|
||||
import org.amnezia.vpn.shadowsocks.core.Core
|
||||
import org.amnezia.vpn.shadowsocks.core.net.Subnet
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.BaseSorter
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.URLSorter
|
||||
import org.amnezia.vpn.shadowsocks.core.preference.DataStore
|
||||
import org.amnezia.vpn.shadowsocks.core.utils.asIterable
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.Reader
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.net.URLConnection
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class Acl {
|
||||
companion object {
|
||||
const val TAG = "Acl"
|
||||
const val ALL = "all"
|
||||
const val BYPASS_LAN = "bypass-lan"
|
||||
const val BYPASS_CHN = "bypass-china"
|
||||
@@ -48,73 +23,48 @@ class Acl {
|
||||
const val GFWLIST = "gfwlist"
|
||||
const val CHINALIST = "china-list"
|
||||
const val CUSTOM_RULES = "custom-rules"
|
||||
const val CUSTOM_RULES_USER = "custom-rules-user"
|
||||
|
||||
private val networkAclParser = "^IMPORT_URL\\s*<(.+)>\\s*$".toRegex()
|
||||
val networkAclParser = "^IMPORT_URL\\s*<(.+)>\\s*$".toRegex()
|
||||
|
||||
fun getFile(id: String, context: Context = Core.deviceStorage) = File(context.noBackupFilesDir, "$id.acl")
|
||||
|
||||
var customRules: Acl
|
||||
get() {
|
||||
val acl = Acl()
|
||||
val file = getFile(CUSTOM_RULES_USER)
|
||||
if (file.canRead()) acl.fromReader(file.reader(), true)
|
||||
val str = DataStore.publicStore.getString(CUSTOM_RULES)
|
||||
if (str != null) acl.fromReader(str.reader(), true)
|
||||
if (!acl.bypass) {
|
||||
acl.bypass = true
|
||||
acl.subnets.clear()
|
||||
}
|
||||
return acl
|
||||
}
|
||||
set(value) = getFile(CUSTOM_RULES_USER).writeText(value.toString())
|
||||
set(value) = DataStore.publicStore.putString(CUSTOM_RULES,
|
||||
if ((!value.bypass || value.subnets.size() == 0) && value.bypassHostnames.size() == 0 &&
|
||||
value.proxyHostnames.size() == 0 && value.urls.size() == 0) null else value.toString())
|
||||
fun save(id: String, acl: Acl) = getFile(id).writeText(acl.toString())
|
||||
|
||||
suspend fun <T> parse(reader: Reader, bypassHostnames: (String) -> T, proxyHostnames: (String) -> T,
|
||||
urls: ((URL) -> T)? = null, defaultBypass: Boolean = false): Pair<Boolean, List<Subnet>> {
|
||||
var bypass = defaultBypass
|
||||
val bypassSubnets = mutableListOf<Subnet>()
|
||||
val proxySubnets = mutableListOf<Subnet>()
|
||||
var hostnames: ((String) -> T)? = if (defaultBypass) proxyHostnames else bypassHostnames
|
||||
var subnets: MutableList<Subnet>? = if (defaultBypass) proxySubnets else bypassSubnets
|
||||
reader.useLines {
|
||||
for (line in it) {
|
||||
coroutineContext[Job]!!.ensureActive()
|
||||
val input = (if (urls == null) line else {
|
||||
val blocks = line.split('#', limit = 2)
|
||||
val url = networkAclParser.matchEntire(blocks.getOrElse(1) { "" })?.groupValues?.getOrNull(1)
|
||||
if (url != null) urls(URL(url))
|
||||
blocks[0]
|
||||
}).trim()
|
||||
if (input.getOrNull(0) == '[') when (input) {
|
||||
"[outbound_block_list]" -> {
|
||||
hostnames = null
|
||||
subnets = null
|
||||
}
|
||||
"[black_list]", "[bypass_list]" -> {
|
||||
hostnames = bypassHostnames
|
||||
subnets = bypassSubnets
|
||||
}
|
||||
"[white_list]", "[proxy_list]" -> {
|
||||
hostnames = proxyHostnames
|
||||
subnets = proxySubnets
|
||||
}
|
||||
"[reject_all]", "[bypass_all]" -> bypass = true
|
||||
"[accept_all]", "[proxy_all]" -> bypass = false
|
||||
else -> error("Unrecognized block: $input")
|
||||
} else if (subnets != null && input.isNotEmpty()) {
|
||||
val subnet = Subnet.fromString(input)
|
||||
if (subnet == null) hostnames!!(input) else subnets!!.add(subnet)
|
||||
}
|
||||
}
|
||||
}
|
||||
return bypass to if (bypass) proxySubnets else bypassSubnets
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class BaseSorter<T> : SortedList.Callback<T>() {
|
||||
override fun onInserted(position: Int, count: Int) { }
|
||||
override fun areContentsTheSame(oldItem: T?, newItem: T?): Boolean = oldItem == newItem
|
||||
override fun onMoved(fromPosition: Int, toPosition: Int) { }
|
||||
override fun onChanged(position: Int, count: Int) { }
|
||||
override fun onRemoved(position: Int, count: Int) { }
|
||||
override fun areItemsTheSame(item1: T?, item2: T?): Boolean = item1 == item2
|
||||
override fun compare(o1: T?, o2: T?): Int =
|
||||
if (o1 == null) if (o2 == null) 0 else 1 else if (o2 == null) -1 else compareNonNull(o1, o2)
|
||||
abstract fun compareNonNull(o1: T, o2: T): Int
|
||||
}
|
||||
private open class DefaultSorter<T : Comparable<T>> : BaseSorter<T>() {
|
||||
override fun compareNonNull(o1: T, o2: T): Int = o1.compareTo(o2)
|
||||
}
|
||||
private object StringSorter : DefaultSorter<String>()
|
||||
private object SubnetSorter : DefaultSorter<Subnet>()
|
||||
private object URLSorter : BaseSorter<URL>() {
|
||||
private val ordering = compareBy<URL>({ it.host }, { it.port }, { it.file }, { it.protocol })
|
||||
override fun compareNonNull(o1: URL, o2: URL): Int = ordering.compare(o1, o2)
|
||||
}
|
||||
|
||||
val bypassHostnames = SortedList(String::class.java, StringSorter)
|
||||
val proxyHostnames = SortedList(String::class.java, StringSorter)
|
||||
@@ -139,11 +89,40 @@ class Acl {
|
||||
proxyHostnames.clear()
|
||||
subnets.clear()
|
||||
urls.clear()
|
||||
val (bypass, subnets) = runBlocking {
|
||||
parse(reader, bypassHostnames::add, proxyHostnames::add, urls::add, defaultBypass)
|
||||
bypass = defaultBypass
|
||||
val bypassSubnets by lazy { SortedList(Subnet::class.java, SubnetSorter) }
|
||||
val proxySubnets by lazy { SortedList(Subnet::class.java, SubnetSorter) }
|
||||
var hostnames: SortedList<String>? = if (defaultBypass) proxyHostnames else bypassHostnames
|
||||
var subnets: SortedList<Subnet>? = if (defaultBypass) proxySubnets else bypassSubnets
|
||||
reader.useLines {
|
||||
for (line in it) {
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
val blocks = (line as java.lang.String).split("#", 2)
|
||||
val url = networkAclParser.matchEntire(blocks.getOrElse(1) { "" })?.groupValues?.getOrNull(1)
|
||||
if (url != null) urls.add(URL(url))
|
||||
when (val input = blocks[0].trim()) {
|
||||
"[outbound_block_list]" -> {
|
||||
hostnames = null
|
||||
subnets = null
|
||||
}
|
||||
"[black_list]", "[bypass_list]" -> {
|
||||
hostnames = bypassHostnames
|
||||
subnets = bypassSubnets
|
||||
}
|
||||
"[white_list]", "[proxy_list]" -> {
|
||||
hostnames = proxyHostnames
|
||||
subnets = proxySubnets
|
||||
}
|
||||
"[reject_all]", "[bypass_all]" -> bypass = true
|
||||
"[accept_all]", "[proxy_all]" -> bypass = false
|
||||
else -> if (subnets != null && input.isNotEmpty()) {
|
||||
val subnet = Subnet.fromString(input)
|
||||
if (subnet == null) hostnames!!.add(input) else subnets!!.add(subnet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.bypass = bypass
|
||||
for (item in subnets) this.subnets.add(item)
|
||||
for (item in (if (bypass) proxySubnets else bypassSubnets).asIterable()) this.subnets.add(item)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -153,13 +132,14 @@ class Acl {
|
||||
|
||||
suspend fun flatten(depth: Int, connect: suspend (URL) -> URLConnection): Acl {
|
||||
if (depth > 0) for (url in urls.asIterable()) {
|
||||
val child = Acl().fromReader(connect(url).also {
|
||||
(it as? HttpURLConnection)?.instanceFollowRedirects = true
|
||||
}.getInputStream().bufferedReader(), bypass)
|
||||
child.flatten(depth - 1, connect)
|
||||
val child = Acl()
|
||||
try {
|
||||
child.fromReader(connect(url).getInputStream().bufferedReader(), bypass).flatten(depth - 1, connect)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
continue
|
||||
}
|
||||
if (bypass != child.bypass) {
|
||||
Timber.w("Imported network ACL has a conflicting mode set. " +
|
||||
"This will probably not work as intended. URL: $url")
|
||||
child.subnets.clear() // subnets for the different mode are discarded
|
||||
child.bypass = bypass
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user