├── app
├── .gitignore
├── executableSo
│ └── .gitignore
├── src
│ └── main
│ │ ├── assets
│ │ ├── yacd.version.txt
│ │ ├── yacd.zip
│ │ └── LICENSE
│ │ ├── res
│ │ ├── resources.properties
│ │ ├── raw-zh-rCN
│ │ │ ├── insecure.txt
│ │ │ ├── not_encrypted.txt
│ │ │ ├── shadowsocks_stream_cipher.txt
│ │ │ └── vmess_md5_auth.txt
│ │ ├── font
│ │ │ └── jetbrains_mono.ttf
│ │ ├── xml
│ │ │ ├── cache_paths.xml
│ │ │ ├── network_security_config.xml
│ │ │ ├── neko_preferences.xml
│ │ │ ├── name_preferences.xml
│ │ │ ├── backup_descriptor.xml
│ │ │ ├── backup_rules.xml
│ │ │ ├── config_preferences.xml
│ │ │ ├── shortcuts.xml
│ │ │ └── balancer_preferences.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── dimens.xml
│ │ │ └── attrs.xml
│ │ ├── raw
│ │ │ ├── insecure.txt
│ │ │ ├── not_encrypted.txt
│ │ │ ├── shadowsocks_stream_cipher.txt
│ │ │ └── vmess_md5_auth.txt
│ │ ├── values-night
│ │ │ └── colors.xml
│ │ ├── menu
│ │ │ ├── traffic_menu.xml
│ │ │ ├── yacd_menu.xml
│ │ │ ├── import_asset_menu.xml
│ │ │ ├── profile_apply_menu.xml
│ │ │ ├── scanner_menu.xml
│ │ │ ├── add_group_menu.xml
│ │ │ ├── app_list_menu.xml
│ │ │ ├── add_route_menu.xml
│ │ │ ├── logcat_menu.xml
│ │ │ ├── per_app_proxy_menu.xml
│ │ │ ├── traffic_item_menu.xml
│ │ │ ├── group_action_menu.xml
│ │ │ ├── profile_config_menu.xml
│ │ │ └── profile_share_menu.xml
│ │ ├── layout
│ │ │ ├── layout_empty.xml
│ │ │ ├── layout_mtu_help.xml
│ │ │ ├── layout_loglevel_help.xml
│ │ │ ├── layout_webview.xml
│ │ │ ├── layout_config_settings.xml
│ │ │ ├── layout_settings_activity.xml
│ │ │ ├── layout_profile_list.xml
│ │ │ ├── layout_progress.xml
│ │ │ ├── layout_appbar.xml
│ │ │ ├── layout_debug.xml
│ │ │ ├── layout_add_entity.xml
│ │ │ ├── layout_empty_route.xml
│ │ │ ├── layout_app_placeholder.xml
│ │ │ ├── layout_scanner.xml
│ │ │ ├── layout_progress_list.xml
│ │ │ ├── simple_menu_dropdown_item.xml
│ │ │ ├── item_keyboard_key.xml
│ │ │ ├── layout_loading.xml
│ │ │ ├── layout_group.xml
│ │ │ ├── layout_route.xml
│ │ │ ├── layout_assets.xml
│ │ │ ├── layout_logcat.xml
│ │ │ ├── layout_tools.xml
│ │ │ └── layout_group_list.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ ├── color
│ │ │ ├── navigation_item.xml
│ │ │ ├── navigation_icon.xml
│ │ │ ├── chip_text_color.xml
│ │ │ ├── chip_background.xml
│ │ │ └── chip_ripple_color.xml
│ │ ├── drawable
│ │ │ ├── ic_baseline_home_24.xml
│ │ │ ├── baseline_keyboard_tab_24.xml
│ │ │ ├── ic_baseline_download_24.xml
│ │ │ ├── ic_baseline_fast_forward_24.xml
│ │ │ ├── ic_baseline_fiber_manual_record_24.xml
│ │ │ ├── ic_baseline_warning_24.xml
│ │ │ ├── ic_file_file_upload.xml
│ │ │ ├── baseline_send_24.xml
│ │ │ ├── ic_action_done.xml
│ │ │ ├── ic_baseline_local_bar_24.xml
│ │ │ ├── ic_navigation_menu.xml
│ │ │ ├── ic_baseline_grid_3x3_24.xml
│ │ │ ├── baseline_arrow_back_24.xml
│ │ │ ├── ic_baseline_info_24.xml
│ │ │ ├── baseline_redo_24.xml
│ │ │ ├── baseline_undo_24.xml
│ │ │ ├── baseline_widgets_24.xml
│ │ │ ├── ic_action_delete.xml
│ │ │ ├── ic_baseline_legend_toggle_24.xml
│ │ │ ├── ic_baseline_layers_24.xml
│ │ │ ├── ic_baseline_transform_24.xml
│ │ │ ├── ic_navigation_close.xml
│ │ │ ├── ic_baseline_compare_arrows_24.xml
│ │ │ ├── ic_baseline_person_24.xml
│ │ │ ├── ic_qu_shadowsocks_foreground.xml
│ │ │ ├── baseline_delete_sweep_24.xml
│ │ │ ├── ic_baseline_airplanemode_active_24.xml
│ │ │ ├── ic_baseline_format_align_left_24.xml
│ │ │ ├── ic_baseline_security_24.xml
│ │ │ ├── ic_image_photo.xml
│ │ │ ├── ic_navigation_apps.xml
│ │ │ ├── ic_av_playlist_add.xml
│ │ │ ├── ic_baseline_view_list_24.xml
│ │ │ ├── baseline_save_24.xml
│ │ │ ├── ic_action_description.xml
│ │ │ ├── ic_baseline_low_priority_24.xml
│ │ │ ├── ic_baseline_location_on_24.xml
│ │ │ ├── ic_image_edit.xml
│ │ │ ├── baseline_wrap_text_24.xml
│ │ │ ├── ic_baseline_push_pin_24.xml
│ │ │ ├── ic_baseline_vpn_key_24.xml
│ │ │ ├── ic_baseline_more_vert_24.xml
│ │ │ ├── ic_baseline_shuffle_24.xml
│ │ │ ├── ic_maps_directions.xml
│ │ │ ├── ic_service_busy.xml
│ │ │ ├── baseline_developer_board_24.xml
│ │ │ ├── ic_action_note_add.xml
│ │ │ ├── ic_qu_camera_launcher.xml
│ │ │ ├── ic_baseline_domain_24.xml
│ │ │ ├── ic_baseline_refresh_24.xml
│ │ │ ├── baseline_flight_takeoff_24.xml
│ │ │ ├── ic_communication_phonelink_ring.xml
│ │ │ ├── ic_image_looks_6.xml
│ │ │ ├── ic_qu_shadowsocks_launcher.xml
│ │ │ ├── terminal_scroll_shape.xml
│ │ │ ├── ic_baseline_running_with_errors_24.xml
│ │ │ ├── ic_maps_360.xml
│ │ │ ├── ic_baseline_link_24.xml
│ │ │ ├── ic_baseline_speed_24.xml
│ │ │ ├── ic_baseline_timelapse_24.xml
│ │ │ ├── ic_baseline_http_24.xml
│ │ │ ├── ic_notification_enhanced_encryption.xml
│ │ │ ├── ic_action_lock_open.xml
│ │ │ ├── ic_baseline_nfc_24.xml
│ │ │ ├── ic_baseline_https_24.xml
│ │ │ ├── ic_baseline_lock_24.xml
│ │ │ ├── ic_action_lock.xml
│ │ │ ├── ic_device_data_usage.xml
│ │ │ ├── ic_device_developer_mode.xml
│ │ │ ├── ic_file_cloud_queue.xml
│ │ │ ├── ic_image_camera_alt.xml
│ │ │ ├── ic_baseline_cast_connected_24.xml
│ │ │ ├── ic_baseline_rule_folder_24.xml
│ │ │ ├── ic_baseline_manage_search_24.xml
│ │ │ ├── ic_baseline_center_focus_weak_24.xml
│ │ │ ├── ic_baseline_update_24.xml
│ │ │ ├── ic_baseline_multiline_chart_24.xml
│ │ │ ├── ic_baseline_texture_24.xml
│ │ │ ├── baseline_translate_24.xml
│ │ │ ├── ic_baseline_emoji_emotions_24.xml
│ │ │ ├── ic_action_dns.xml
│ │ │ ├── ic_baseline_android_24.xml
│ │ │ ├── baseline_public_24.xml
│ │ │ ├── ic_hardware_router.xml
│ │ │ ├── ic_baseline_multiple_stop_24.xml
│ │ │ ├── ic_baseline_sanitizer_24.xml
│ │ │ ├── ic_baseline_wb_sunny_24.xml
│ │ │ ├── ic_baseline_nat_24.xml
│ │ │ ├── ic_baseline_no_encryption_gmailerrorred_24.xml
│ │ │ ├── ic_baseline_import_contacts_24.xml
│ │ │ ├── ic_baseline_bug_report_24.xml
│ │ │ ├── ic_baseline_transgender_24.xml
│ │ │ ├── ic_baseline_camera_24.xml
│ │ │ ├── ic_social_share.xml
│ │ │ ├── ic_maps_directions_boat.xml
│ │ │ ├── ic_baseline_card_giftcard_24.xml
│ │ │ ├── ic_baseline_color_lens_24.xml
│ │ │ ├── ic_baseline_flip_camera_android_24.xml
│ │ │ ├── baseline_construction_24.xml
│ │ │ ├── ic_app_shortcut_background.xml
│ │ │ ├── ic_service_idle.xml
│ │ │ ├── ic_baseline_add_road_24.xml
│ │ │ ├── ic_baseline_shutter_speed_24.xml
│ │ │ ├── ic_baseline_stream_24.xml
│ │ │ ├── ic_action_settings.xml
│ │ │ ├── ic_service_connected.xml
│ │ │ ├── ic_service_stopping.xml
│ │ │ └── ic_action_copyright.xml
│ │ ├── drawable-v26
│ │ │ ├── ic_qu_camera_launcher.xml
│ │ │ └── ic_qu_shadowsocks_launcher.xml
│ │ ├── values-nl
│ │ │ └── strings.xml
│ │ ├── values-it
│ │ │ └── strings.xml
│ │ ├── values-ko
│ │ │ └── strings.xml
│ │ └── values-pt-rBR
│ │ │ └── strings.xml
│ │ ├── aidl
│ │ └── io
│ │ │ └── nekohasekai
│ │ │ └── sagernet
│ │ │ └── aidl
│ │ │ ├── TrafficData.aidl
│ │ │ ├── SpeedDisplayData.aidl
│ │ │ ├── ISagerNetService.aidl
│ │ │ └── ISagerNetServiceCallback.aidl
│ │ ├── ic_launcher-playstore.png
│ │ └── java
│ │ ├── io
│ │ └── nekohasekai
│ │ │ └── sagernet
│ │ │ ├── bg
│ │ │ ├── AbstractInstance.kt
│ │ │ ├── proto
│ │ │ │ └── UrlTest.kt
│ │ │ └── ProxyService.kt
│ │ │ ├── ui
│ │ │ ├── profile
│ │ │ │ ├── HttpSettingsActivity.kt
│ │ │ │ ├── TrojanSettingsActivity.kt
│ │ │ │ └── VMessSettingsActivity.kt
│ │ │ ├── NamedFragment.kt
│ │ │ ├── BlankActivity.kt
│ │ │ ├── SettingsFragment.kt
│ │ │ ├── NetworkFragment.kt
│ │ │ ├── ToolbarFragment.kt
│ │ │ ├── ProfileSelectActivity.kt
│ │ │ ├── SwitchActivity.kt
│ │ │ └── ToolsFragment.kt
│ │ │ ├── aidl
│ │ │ ├── TrafficData.kt
│ │ │ └── SpeedDisplayData.kt
│ │ │ ├── database
│ │ │ ├── preference
│ │ │ │ ├── OnPreferenceDataStoreChangeListener.kt
│ │ │ │ └── PublicDatabase.kt
│ │ │ ├── ParcelizeBridge.java
│ │ │ └── StringCollectionConverter.kt
│ │ │ ├── ktx
│ │ │ ├── Dimens.kt
│ │ │ ├── Dialogs.kt
│ │ │ └── Browsers.kt
│ │ │ ├── widget
│ │ │ ├── WindowInsetsListeners.kt
│ │ │ ├── UserAgentPreference.kt
│ │ │ ├── GroupPreference.kt
│ │ │ ├── OutboundPreference.kt
│ │ │ ├── FabProgressBehavior.kt
│ │ │ └── AutoCollapseTextView.kt
│ │ │ └── fmt
│ │ │ ├── internal
│ │ │ └── InternalBean.java
│ │ │ ├── trojan
│ │ │ └── TrojanFmt.kt
│ │ │ ├── ssh
│ │ │ └── SSHFmt.kt
│ │ │ ├── Serializable.kt
│ │ │ ├── gson
│ │ │ └── GsonConverters.java
│ │ │ ├── TypeMap.kt
│ │ │ ├── v2ray
│ │ │ └── VMessBean.java
│ │ │ ├── UniversalFmt.kt
│ │ │ └── http
│ │ │ └── HttpFmt.kt
│ │ ├── com
│ │ └── github
│ │ │ └── shadowsocks
│ │ │ └── plugin
│ │ │ └── Utils.kt
│ │ └── moe
│ │ └── matsuri
│ │ └── nb4a
│ │ ├── proxy
│ │ ├── shadowtls
│ │ │ └── ShadowTLSFmt.kt
│ │ └── PreferenceBindingManager.kt
│ │ ├── ui
│ │ ├── LongClickMenuPreference.kt
│ │ ├── LongClickListPreference.kt
│ │ ├── ConnectionTestNotification.kt
│ │ ├── LongClickSwitchPreference.kt
│ │ └── Dialogs.kt
│ │ ├── TempDatabase.kt
│ │ └── utils
│ │ └── WebViewUtil.kt
└── schemas
│ ├── moe.matsuri.nb4a.TempDatabase
│ └── 1.json
│ └── io.nekohasekai.sagernet.database.preference.PublicDatabase
│ └── 1.json
├── settings.gradle.kts
├── release.keystore
├── libcore
├── assets_other.go
├── stun
│ ├── README
│ └── doc.go
├── .gitignore
├── device
│ ├── device.go
│ └── debug.go
├── fix.go
├── crypto.go
├── assets.go
├── certs.go
├── build.sh
├── LICENSE
├── init.sh
├── platform_java.go
├── interface_monitor.go
├── stun.go
└── geosite.go
├── nb4a.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── repositories.gradle.kts
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request-zh_cn.md
│ ├── feature_request-en.md
│ ├── bug-report-zh_cn.md
│ └── bug-report-en.md
├── AUTHORS
├── .gitignore
├── run
├── LICENSE
└── gradle.properties
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/executableSo/.gitignore:
--------------------------------------------------------------------------------
1 | *.so
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/yacd.version.txt:
--------------------------------------------------------------------------------
1 | 3
--------------------------------------------------------------------------------
/app/src/main/res/resources.properties:
--------------------------------------------------------------------------------
1 | unqualifiedResLocale=en-US
2 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | include(":app")
2 | rootProject.name = "NB4A"
3 |
--------------------------------------------------------------------------------
/app/src/main/res/raw-zh-rCN/insecure.txt:
--------------------------------------------------------------------------------
1 | 该配置 (不安全) 能够被检测识别,传输的内容对审查者完全可见,并且无法抵抗中间人篡改通讯内容.
--------------------------------------------------------------------------------
/app/src/main/res/raw-zh-rCN/not_encrypted.txt:
--------------------------------------------------------------------------------
1 | 该配置 (未加密) 极易被检测识别,传输的内容对审查者完全可见,并且无法抵抗中间人篡改通讯内容.
--------------------------------------------------------------------------------
/release.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/release.keystore
--------------------------------------------------------------------------------
/libcore/assets_other.go:
--------------------------------------------------------------------------------
1 | //go:build !android
2 |
3 | package libcore
4 |
5 | func extractAssets() {}
6 |
--------------------------------------------------------------------------------
/libcore/stun/README:
--------------------------------------------------------------------------------
1 | from https://github.com/ccding/go-stun/commit/877ebaff7ba7b0f0ce44e92d785075647545e777
2 |
--------------------------------------------------------------------------------
/libcore/.gitignore:
--------------------------------------------------------------------------------
1 | binary*.go
2 | *.[a|j]ar
3 | .idea
4 | .vscode
5 | /debug.go
6 | build
7 | .build
8 | env_*.sh
9 |
--------------------------------------------------------------------------------
/app/src/main/assets/yacd.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/assets/yacd.zip
--------------------------------------------------------------------------------
/nb4a.properties:
--------------------------------------------------------------------------------
1 | PACKAGE_NAME=moe.nb4a
2 | VERSION_NAME=1.4.1
3 | PRE_VERSION_NAME=pre-1.4.1-20251026-2
4 | VERSION_CODE=45
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/aidl/io/nekohasekai/sagernet/aidl/TrafficData.aidl:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.aidl;
2 |
3 | parcelable TrafficData;
4 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/aidl/io/nekohasekai/sagernet/aidl/SpeedDisplayData.aidl:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.aidl;
2 |
3 | parcelable SpeedDisplayData;
4 |
--------------------------------------------------------------------------------
/app/src/main/res/font/jetbrains_mono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/font/jetbrains_mono.ttf
--------------------------------------------------------------------------------
/app/src/main/res/xml/cache_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/repositories.gradle.kts:
--------------------------------------------------------------------------------
1 | repositories {
2 | google()
3 | mavenCentral()
4 | gradlePluginPortal()
5 | maven(url = "https://jitpack.io")
6 | }
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatsuriDayo/NekoBoxForAndroid/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/raw-zh-rCN/shadowsocks_stream_cipher.txt:
--------------------------------------------------------------------------------
1 | 该配置 (Shadowsocks 流式密码) 可以被准确地主动探测、在不需要密码的情况下被审查者解密流量, 且服务端开启 IV 重放过滤器也无法缓解.
2 |
3 | 了解更多: https://github.com/net4people/bbs/issues/24
--------------------------------------------------------------------------------
/app/src/main/res/raw-zh-rCN/vmess_md5_auth.txt:
--------------------------------------------------------------------------------
1 | 该配置 (VMess MD5 认证) 抗篡改能力存疑, 隐蔽性存疑, 已被上游废弃.
2 |
3 | 自 2022 年 1 月 1 日起, 服务器端将默认禁用对于 MD5 认证信息 的兼容. 任何使用 MD5 认证信息的客户端将无法连接到禁用 VMess MD5 认证信息的服务器端.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request-zh_cn.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: '功能请求'
3 | about: '对软件的新功能提出建议。'
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 描述建议
11 |
12 | ## 建议的必要性
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/bg/AbstractInstance.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.bg
2 |
3 | import java.io.Closeable
4 |
5 | interface AbstractInstance : Closeable {
6 |
7 | fun launch()
8 |
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 264dp
3 | 88dp
4 | 8dp
5 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/insecure.txt:
--------------------------------------------------------------------------------
1 | The configuration (insecure) can be detected and identified, the transmission is fully visible to the censor and is not resistant to man-in-the-middle tampering with the content of the communication.
--------------------------------------------------------------------------------
/app/src/main/java/com/github/shadowsocks/plugin/Utils.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Utils")
2 |
3 | package com.github.shadowsocks.plugin
4 |
5 | import android.os.Parcelable
6 | import kotlinx.parcelize.Parcelize
7 |
8 | @Parcelize
9 | class Empty : Parcelable
--------------------------------------------------------------------------------
/app/src/main/res/raw/not_encrypted.txt:
--------------------------------------------------------------------------------
1 | This configuration (not encrypted) is extremely easy to detect and identify, the transmission is fully visible to the censor, and there is no resistance to man-in-the-middle tampering with the content of the communication.
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/material_light_white
4 | #303030
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
3 | distributionPath=wrapper/dists
4 | zipStorePath=wrapper/dists
5 | zipStoreBase=GRADLE_USER_HOME
6 |
--------------------------------------------------------------------------------
/libcore/device/device.go:
--------------------------------------------------------------------------------
1 | package device
2 |
3 | import (
4 | "runtime"
5 | )
6 |
7 | func NumUDPWorkers() int {
8 | numUDPWorkers := 4
9 | if num := runtime.GOMAXPROCS(0); num > numUDPWorkers {
10 | numUDPWorkers = num
11 | }
12 | return numUDPWorkers
13 | }
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request-en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 'Feature Request'
3 | about: 'Make suggestions for new features of the software'
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Description suggestions
11 |
12 | ## Necessity of recommendations
13 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/traffic_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/profile/HttpSettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui.profile
2 |
3 | import io.nekohasekai.sagernet.fmt.http.HttpBean
4 |
5 | class HttpSettingsActivity : StandardV2RaySettingsActivity() {
6 |
7 | override fun createEntity() = HttpBean()
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/libcore/fix.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | // https://github.com/golang/go/issues/46893
4 | // TODO: remove after `bulkBarrierPreWrite: unaligned arguments` fixed
5 |
6 | type StringBox struct {
7 | Value string
8 | }
9 |
10 | func wrapString(value string) *StringBox {
11 | return &StringBox{Value: value}
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/profile/TrojanSettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui.profile
2 |
3 | import io.nekohasekai.sagernet.fmt.trojan.TrojanBean
4 |
5 | class TrojanSettingsActivity : StandardV2RaySettingsActivity() {
6 |
7 | override fun createEntity() = TrojanBean()
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/shadowsocks_stream_cipher.txt:
--------------------------------------------------------------------------------
1 | This configuration (Shadowsocks streaming cipher) can be accurately proactively detected and decrypted by censors without requiring a password, and cannot be mitigated by turning on IV replay filters on the server side.
2 |
3 | Learn more: https://github.com/net4people/bbs/issues/24
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/aidl/TrafficData.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.aidl
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class TrafficData(
8 | var id: Long = 0L,
9 | var tx: Long = 0L,
10 | var rx: Long = 0L,
11 | ) : Parcelable
12 |
--------------------------------------------------------------------------------
/app/src/main/res/color/navigation_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report-zh_cn.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: '问题反馈'
3 | about: '在提出问题前请先自行排除服务器端问题和升级到最新客户端。'
4 | title: 'BUG: '
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 描述问题
11 |
12 | 预期行为:
13 |
14 | 实际行为:
15 |
16 | ## 如何复现
17 |
18 | 提供有帮助的截图,录像,文字说明,订阅链接等。
19 |
20 | ## 日志
21 |
22 | 如果有日志,请上传。请在文档内查看导出日志的详细步骤。
23 |
--------------------------------------------------------------------------------
/app/src/main/res/color/navigation_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/neko_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/database/preference/OnPreferenceDataStoreChangeListener.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.database.preference
2 |
3 | import androidx.preference.PreferenceDataStore
4 |
5 | interface OnPreferenceDataStoreChangeListener {
6 | fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String)
7 | }
8 |
--------------------------------------------------------------------------------
/libcore/crypto.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | import (
4 | "crypto/sha1"
5 | "crypto/sha256"
6 | "encoding/hex"
7 | )
8 |
9 | func Sha1(data []byte) []byte {
10 | sum := sha1.Sum(data)
11 | return sum[:]
12 | }
13 |
14 | func Sha256Hex(data []byte) string {
15 | sum := sha256.Sum256(data)
16 | return hex.EncodeToString(sum[:])
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/name_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | SagerNet was originally created in late 2021, by
2 | nekohasekai .
3 |
4 | Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
5 | people who have submitted patches, fixed bugs, added translations, and
6 | generally made SagerNet that much better:
7 |
8 | https://github.com/SagerNet/SagerNet/graphs/contributors
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_mtu_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | .idea
4 | .vscode
5 | .DS_Store
6 | build/
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | local.properties
11 | /app/libs/
12 | /app/src/main/assets/sing-box
13 | /service_account_credentials.json
14 | jniLibs/
15 | /library/libcore_build/
16 | .idea/deploymentTargetDropDown.xml
17 | /nkmr
18 |
19 | # submodules
20 | /external
21 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/yacd_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_loglevel_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | EXEC=""
4 | TARGET="buildScript"
5 | declare -A PARAMS
6 | declare -i INDEX=0
7 |
8 | for e in $@; do
9 | TARGET="$TARGET/$e"
10 | PARAMS[$INDEX]=$e
11 | INDEX=$INDEX+1
12 | shift
13 | if [ -x "${TARGET}.sh" ]; then
14 | EXEC="${TARGET}.sh"
15 | PARAMS=()
16 | INDEX=0
17 | fi
18 | done
19 |
20 | echo ">> $EXEC"
21 | exec "$EXEC" $PARAMS
22 |
--------------------------------------------------------------------------------
/libcore/assets.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | const (
4 | geoipDat = "geoip.db"
5 | geositeDat = "geosite.db"
6 | geoipVersion = "geoip.version.txt"
7 | geositeVersion = "geosite.version.txt"
8 |
9 | yacdDstFolder = "yacd"
10 | yacdVersion = "yacd.version.txt"
11 | )
12 |
13 | var apkAssetPrefixSingBox = "sing-box/"
14 | var internalAssetsPath string
15 | var externalAssetsPath string
16 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ktx/Dimens.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ktx
2 |
3 | import android.content.res.Resources
4 | import kotlin.math.ceil
5 |
6 | private val density = Resources.getSystem().displayMetrics.density
7 |
8 | fun dp2pxf(dpValue: Int): Float {
9 | return density * dpValue
10 | }
11 |
12 | fun dp2px(dpValue: Int): Int {
13 | return ceil(dp2pxf(dpValue)).toInt()
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/database/ParcelizeBridge.java:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.database;
2 |
3 | import android.os.Parcel;
4 |
5 | /**
6 | * see: https://youtrack.jetbrains.com/issue/KT-19853
7 | */
8 | public class ParcelizeBridge {
9 |
10 | public static RuleEntity createRule(Parcel parcel) {
11 | return (RuleEntity) RuleEntity.CREATOR.createFromParcel(parcel);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/NamedFragment.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | abstract class NamedFragment : Fragment {
6 |
7 | constructor() : super()
8 | constructor(contentLayoutId: Int) : super(contentLayoutId)
9 |
10 | private val name by lazy { name0() }
11 | fun name() = name
12 | protected abstract fun name0(): String
13 |
14 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/import_asset_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_home_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/vmess_md5_auth.txt:
--------------------------------------------------------------------------------
1 | This configuration (VMess MD5 authentication) has been deprecated by upstream because of its questionable resistance to tampering and concealment.
2 |
3 | As of January 1, 2022, compatibility with MD5 authentication information will be disabled on the server side by default. Any client using MD5 authentication information will not be able to connect to a server with VMess MD5 authentication information disabled.
--------------------------------------------------------------------------------
/app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetService.aidl:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.aidl;
2 |
3 | import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback;
4 |
5 | interface ISagerNetService {
6 | int getState();
7 | String getProfileName();
8 |
9 | void registerCallback(in ISagerNetServiceCallback cb, int id);
10 | oneway void unregisterCallback(in ISagerNetServiceCallback cb);
11 |
12 | int urlTest();
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/profile/VMessSettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui.profile
2 |
3 | import io.nekohasekai.sagernet.fmt.v2ray.VMessBean
4 |
5 | class VMessSettingsActivity : StandardV2RaySettingsActivity() {
6 |
7 | override fun createEntity() = VMessBean().apply {
8 | if (intent?.getBooleanExtra("vless", false) == true) {
9 | alterId = -1
10 | }
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_keyboard_tab_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_download_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_fast_forward_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/profile_apply_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/scanner_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_fiber_manual_record_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_warning_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_file_file_upload.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_descriptor.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/bg/proto/UrlTest.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.bg.proto
2 |
3 | import io.nekohasekai.sagernet.database.DataStore
4 | import io.nekohasekai.sagernet.database.ProxyEntity
5 |
6 | class UrlTest {
7 |
8 | val link = DataStore.connectionTestURL
9 | private val timeout = 5000
10 |
11 | suspend fun doTest(profile: ProxyEntity): Int {
12 | return TestInstance(profile, link, timeout).doTest()
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_send_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_done.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_local_bar_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_navigation_menu.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_grid_3x3_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/libcore/device/debug.go:
--------------------------------------------------------------------------------
1 | package device
2 |
3 | import (
4 | "fmt"
5 | "runtime/debug"
6 | )
7 |
8 | var DebugFunc func(interface{})
9 |
10 | func GoDebug(any interface{}) {
11 | if DebugFunc != nil {
12 | go DebugFunc(any)
13 | }
14 | }
15 |
16 | func DeferPanicToError(name string, onError func(error)) {
17 | if r := recover(); r != nil {
18 | if onError != nil {
19 | s := fmt.Errorf("%s panic: %s\n%s", name, r, string(debug.Stack()))
20 | onError(s)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_arrow_back_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_info_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v26/ic_qu_camera_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_redo_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_undo_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_widgets_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_delete.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_legend_toggle_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_layers_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v26/ic_qu_shadowsocks_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_transform_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_navigation_close.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_compare_arrows_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_person_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qu_shadowsocks_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_delete_sweep_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_airplanemode_active_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_format_align_left_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_security_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_photo.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_navigation_apps.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_av_playlist_add.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_view_list_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetServiceCallback.aidl:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.aidl;
2 |
3 | import io.nekohasekai.sagernet.aidl.SpeedDisplayData;
4 | import io.nekohasekai.sagernet.aidl.TrafficData;
5 |
6 | oneway interface ISagerNetServiceCallback {
7 | void stateChanged(int state, String profileName, String msg);
8 | void missingPlugin(String profileName, String pluginName);
9 | void cbSpeedUpdate(in SpeedDisplayData stats);
10 | void cbTrafficUpdate(in TrafficData stats);
11 | void cbSelectorUpdate(long id);
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_save_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_description.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_low_priority_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/widget/WindowInsetsListeners.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.widget
2 |
3 | import android.view.View
4 | import androidx.core.view.OnApplyWindowInsetsListener
5 | import androidx.core.view.WindowInsetsCompat
6 | import androidx.core.view.updatePadding
7 |
8 | object ListListener : OnApplyWindowInsetsListener {
9 | override fun onApplyWindowInsets(view: View, insets: WindowInsetsCompat) = insets.apply {
10 | view.updatePadding(bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_location_on_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_edit.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_wrap_text_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_push_pin_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_vpn_key_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report-en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 'Bug Report'
3 | about: 'Please troubleshoot server-side issues and upgrade to the latest client before raising a question.'
4 | title: 'BUG: '
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Describe the problem
11 |
12 | Expected behavior:
13 |
14 | Actual behavior:
15 |
16 | ## How to reproduce
17 |
18 | Provide helpful screenshots, videos, text descriptions, subscription links, etc.
19 |
20 | ## log
21 |
22 | If you have logs, please upload them. Please see the detailed steps for exporting logs in the documentation.
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_more_vert_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_shuffle_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/aidl/SpeedDisplayData.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.aidl
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class SpeedDisplayData(
8 | // Bytes per second
9 | var txRateProxy: Long = 0L,
10 | var rxRateProxy: Long = 0L,
11 | var txRateDirect: Long = 0L,
12 | var rxRateDirect: Long = 0L,
13 |
14 | // Bytes for the current session
15 | // Outbound "bypass" usage is not counted
16 | var txTotal: Long = 0L,
17 | var rxTotal: Long = 0L,
18 | ) : Parcelable
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_maps_directions.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_webview.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_service_busy.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/BlankActivity.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import moe.matsuri.nb4a.utils.SendLog
6 |
7 | class BlankActivity : AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 |
12 | // process crash log
13 | intent?.getStringExtra("sendLog")?.apply {
14 | SendLog.sendLog(this@BlankActivity, this)
15 | }
16 |
17 | finish()
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_developer_board_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_note_add.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qu_camera_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Foutopsporing Informatie exporteren
4 | Versie (%s)
5 | Versie
6 | Open source-licenties
7 | Telegram-update kanaal
8 | Broncode
9 | Project
10 | De universele proxy-toolchain voor Android, geschreven in Kotlin.
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_domain_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_refresh_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/libcore/certs.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | import (
4 | "crypto/x509"
5 | "log"
6 | _ "unsafe" // for go:linkname
7 | )
8 |
9 | //go:linkname systemRoots crypto/x509.systemRoots
10 | var systemRoots *x509.CertPool
11 |
12 | func updateRootCACerts(pem []byte) {
13 | x509.SystemCertPool()
14 | roots := x509.NewCertPool()
15 | if !roots.AppendCertsFromPEM(pem) {
16 | log.Println("failed to append certificates from pem")
17 | return
18 | }
19 | systemRoots = roots
20 | log.Println("external ca.pem was loaded")
21 | }
22 |
23 | //go:linkname initSystemRoots crypto/x509.initSystemRoots
24 | func initSystemRoots()
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_flight_takeoff_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Esporta informazioni di debug
4 | Versione (%s)
5 | Versione
6 | Licenze open source
7 | Canale di aggiornamento di Telegram
8 | Codice sorgente
9 | Progetto
10 | La toolchain proxy universale per Android, scritta in Kotlin.
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_communication_phonelink_ring.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_looks_6.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qu_shadowsocks_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/terminal_scroll_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_running_with_errors_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_maps_360.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_config_settings.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_link_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_speed_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/add_group_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/internal/InternalBean.java:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt.internal;
2 |
3 | import io.nekohasekai.sagernet.fmt.AbstractBean;
4 |
5 | public abstract class InternalBean extends AbstractBean {
6 |
7 | @Override
8 | public String displayAddress() {
9 | return "";
10 | }
11 |
12 | @Override
13 | public boolean canICMPing() {
14 | return false;
15 | }
16 |
17 | @Override
18 | public boolean canTCPing() {
19 | return false;
20 | }
21 |
22 | @Override
23 | public boolean canMapping() {
24 | return false;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/proxy/shadowtls/ShadowTLSFmt.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.proxy.shadowtls
2 |
3 | import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundTLS
4 | import moe.matsuri.nb4a.SingBoxOptions
5 |
6 | fun buildSingBoxOutboundShadowTLSBean(bean: ShadowTLSBean): SingBoxOptions.Outbound_ShadowTLSOptions {
7 | return SingBoxOptions.Outbound_ShadowTLSOptions().apply {
8 | type = "shadowtls"
9 | server = bean.serverAddress
10 | server_port = bean.serverPort
11 | version = bean.version
12 | password = bean.password
13 | tls = buildSingBoxOutboundTLS(bean)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_timelapse_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_http_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notification_enhanced_encryption.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/color/chip_text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_lock_open.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_nfc_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_https_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_lock_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_lock.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_device_data_usage.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_device_developer_mode.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_file_cloud_queue.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_camera_alt.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_cast_connected_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_rule_folder_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/color/chip_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_manage_search_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_center_focus_weak_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_update_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_multiline_chart_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/app_list_menu.xml:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/libcore/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source ./env_java.sh || true
4 | source ../buildScript/init/env_ndk.sh
5 |
6 | BUILD=".build"
7 |
8 | rm -rf $BUILD/android \
9 | $BUILD/java \
10 | $BUILD/javac-output \
11 | $BUILD/src
12 |
13 | if [ -z "$GOPATH" ]; then
14 | GOPATH=$(go env GOPATH)
15 | fi
16 |
17 | export GOBIND=gobind-matsuri
18 | "$GOPATH"/bin/gomobile-matsuri bind -v -androidapi 21 -cache "$(realpath $BUILD)" -trimpath -ldflags='-s -w' -tags='with_conntrack,with_gvisor,with_quic,with_wireguard,with_utls,with_clash_api' . || exit 1
19 | rm -r libcore-sources.jar
20 |
21 | proj=../app/libs
22 | mkdir -p $proj
23 | cp -f libcore.aar $proj
24 | echo ">> install $(realpath $proj)/libcore.aar"
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_texture_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2021 by nekohasekai
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_translate_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_emoji_emotions_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
11 |
12 |
13 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/trojan/TrojanFmt.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt.trojan
2 |
3 | import io.nekohasekai.sagernet.fmt.v2ray.parseDuckSoft
4 | import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
5 |
6 | fun parseTrojan(server: String): TrojanBean {
7 |
8 | val link = server.replace("trojan://", "https://").toHttpUrlOrNull()
9 | ?: error("invalid trojan link $server")
10 |
11 | return TrojanBean().apply {
12 | parseDuckSoft(link)
13 | link.queryParameter("allowInsecure")
14 | ?.apply { if (this == "1" || this == "true") allowInsecure = true }
15 | link.queryParameter("peer")?.apply { if (this.isNotBlank()) sni = this }
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_dns.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_android_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/libcore/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2021 by nekohasekai
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
--------------------------------------------------------------------------------
/libcore/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | chmod -R 777 .build 2>/dev/null
4 | rm -rf .build 2>/dev/null
5 |
6 | if [ -z "$GOPATH" ]; then
7 | GOPATH=$(go env GOPATH)
8 | fi
9 |
10 | # Install gomobile
11 | if [ ! -f "$GOPATH/bin/gomobile-matsuri" ]; then
12 | git clone https://github.com/MatsuriDayo/gomobile.git
13 | pushd gomobile
14 | git checkout origin/master2
15 | pushd cmd
16 | pushd gomobile
17 | go install -v
18 | popd
19 | pushd gobind
20 | go install -v
21 | popd
22 | popd
23 | rm -rf gomobile
24 | mv "$GOPATH/bin/gomobile" "$GOPATH/bin/gomobile-matsuri"
25 | mv "$GOPATH/bin/gobind" "$GOPATH/bin/gobind-matsuri"
26 | fi
27 |
28 | GOBIND=gobind-matsuri gomobile-matsuri init
29 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/add_route_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_public_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hardware_router.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_multiple_stop_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/assets/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2021 by nekohasekai
2 |
3 |
4 | This program is free software: you can
5 | redistribute it and/or modify it under
6 | the terms of the GNU General Public License
7 | as published by the Free Software Foundation,
8 | either version 3 of the License,
9 | or (at your option) any later version.
10 |
11 | This program is distributed in the hope
12 | that it will be useful, but WITHOUT ANY WARRANTY;
13 | without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 | See the GNU General Public License for more details.
16 |
17 | You should have received a copy of the
18 | GNU General Public License along with this program.
19 | If not, see .
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_sanitizer_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_wb_sunny_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/config_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_nat_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/libcore/platform_java.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | var intfBox BoxPlatformInterface
4 | var intfNB4A NB4AInterface
5 |
6 | var useProcfs bool
7 | var isBgProcess bool
8 |
9 | type NB4AInterface interface {
10 | UseOfficialAssets() bool
11 | Selector_OnProxySelected(selectorTag string, tag string)
12 | }
13 |
14 | type BoxPlatformInterface interface {
15 | AutoDetectInterfaceControl(fd int32) error
16 | OpenTun(singTunOptionsJson, tunPlatformOptionsJson string) (int, error)
17 | UseProcFS() bool
18 | FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
19 | PackageNameByUid(uid int32) (string, error)
20 | UIDByPackageName(packageName string) (int32, error)
21 | WIFIState() string
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_no_encryption_gmailerrorred_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_import_contacts_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.core.view.ViewCompat
6 | import io.nekohasekai.sagernet.R
7 | import io.nekohasekai.sagernet.widget.ListListener
8 |
9 | class SettingsFragment : ToolbarFragment(R.layout.layout_config_settings) {
10 |
11 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
12 | super.onViewCreated(view, savedInstanceState)
13 |
14 | ViewCompat.setOnApplyWindowInsetsListener(view, ListListener)
15 | toolbar.setTitle(R.string.settings)
16 |
17 | parentFragmentManager.beginTransaction()
18 | .replace(R.id.settings, SettingsPreferenceFragment())
19 | .commitAllowingStateLoss()
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/logcat_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_settings_activity.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_bug_report_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_transgender_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/NetworkFragment.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.view.View
6 | import io.nekohasekai.sagernet.R
7 | import io.nekohasekai.sagernet.databinding.LayoutNetworkBinding
8 | import io.nekohasekai.sagernet.ktx.app
9 |
10 | class NetworkFragment : NamedFragment(R.layout.layout_network) {
11 |
12 | override fun name0() = app.getString(R.string.tools_network)
13 |
14 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
15 | super.onViewCreated(view, savedInstanceState)
16 |
17 | val binding = LayoutNetworkBinding.bind(view)
18 | binding.stunTest.setOnClickListener {
19 | startActivity(Intent(requireContext(), StunActivity::class.java))
20 | }
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_camera_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 디버그 정보 내보내기
4 | 버전(%s)
5 | 버전
6 | 오픈 소스 라이선스
7 | 텔레그램 업데이트 채널
8 | 소스 코드
9 | 프로젝트
10 | 코틀린에 기록 된 안드로이드에 대한 보편적 인 프록시 도구 체인.
11 | 비녀장
12 | 그룹 해제
13 | 문서
14 | 테마
15 | 대하여
16 | 그룹
17 | 구성
18 |
--------------------------------------------------------------------------------
/app/src/main/res/color/chip_ripple_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/proxy/PreferenceBindingManager.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.proxy
2 |
3 | import androidx.preference.PreferenceFragmentCompat
4 |
5 |
6 | class PreferenceBindingManager {
7 | val items = mutableListOf()
8 |
9 | fun add(b: PreferenceBinding): PreferenceBinding {
10 | items.add(b)
11 | return b
12 | }
13 |
14 | fun fromCacheAll(bean: Any) {
15 | items.forEach {
16 | it.bean = bean
17 | it.fromCache()
18 | }
19 | }
20 |
21 | fun writeToCacheAll(bean: Any) {
22 | items.forEach {
23 | it.bean = bean
24 | it.writeToCache()
25 | }
26 | }
27 |
28 | fun setPreferenceFragment(pf: PreferenceFragmentCompat) {
29 | items.forEach {
30 | it.pf = pf
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_social_share.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_profile_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_maps_directions_boat.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_card_giftcard_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_color_lens_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ktx/Dialogs.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ktx
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import androidx.appcompat.app.AlertDialog
6 | import androidx.fragment.app.Fragment
7 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
8 | import io.nekohasekai.sagernet.R
9 |
10 | fun Context.alert(text: String): AlertDialog {
11 | return MaterialAlertDialogBuilder(this).setTitle(R.string.error_title)
12 | .setMessage(text)
13 | .setPositiveButton(android.R.string.ok, null)
14 | .create()
15 | }
16 |
17 | fun Fragment.alert(text: String) = requireContext().alert(text)
18 |
19 | fun AlertDialog.tryToShow() {
20 | try {
21 | val activity = context as Activity
22 | if (!activity.isFinishing) {
23 | show()
24 | }
25 | } catch (e: Exception) {
26 | Logs.e(e)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/per_app_proxy_menu.xml:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/libcore/stun/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 Cong Ding
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package stun is a STUN (RFC 3489 and RFC 5389) client implementation in
16 | // golang.
17 | //
18 | // It is extremely easy to use -- just one line of code.
19 | //
20 | // nat, host, err := stun.NewClient().Discover()
21 | //
22 | // More details please go to `main.go`.
23 | package stun
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_construction_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_app_shortcut_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/ssh/SSHFmt.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt.ssh
2 |
3 | import moe.matsuri.nb4a.SingBoxOptions
4 | import moe.matsuri.nb4a.utils.listByLineOrComma
5 |
6 | fun buildSingBoxOutboundSSHBean(bean: SSHBean): SingBoxOptions.Outbound_SSHOptions {
7 | return SingBoxOptions.Outbound_SSHOptions().apply {
8 | type = "ssh"
9 | server = bean.serverAddress
10 | server_port = bean.serverPort
11 | user = bean.username
12 | if (bean.publicKey.isNotBlank()) {
13 | host_key = bean.publicKey.listByLineOrComma()
14 | }
15 | when (bean.authType) {
16 | SSHBean.AUTH_TYPE_PRIVATE_KEY -> {
17 | private_key = bean.privateKey
18 | private_key_passphrase = bean.privateKeyPassphrase
19 | }
20 | else -> {
21 | password = bean.password
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_appbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_debug.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_service_idle.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/widget/UserAgentPreference.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.widget
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import androidx.core.content.res.TypedArrayUtils
6 | import androidx.preference.EditTextPreference
7 | import io.nekohasekai.sagernet.R
8 | import io.nekohasekai.sagernet.ktx.USER_AGENT
9 |
10 | class UserAgentPreference
11 | @JvmOverloads constructor(
12 | context: Context, attrs: AttributeSet? = null, defStyle: Int = TypedArrayUtils.getAttr(
13 | context, R.attr.editTextPreferenceStyle, android.R.attr.editTextPreferenceStyle
14 | )
15 | ) : EditTextPreference(context, attrs, defStyle) {
16 |
17 | public override fun notifyChanged() {
18 | super.notifyChanged()
19 | }
20 |
21 | override fun getSummary(): CharSequence? {
22 | if (text.isNullOrBlank()) {
23 | return USER_AGENT
24 | }
25 | return super.getSummary()
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_add_road_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
19 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/Serializable.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt
2 |
3 | import android.os.Parcel
4 | import android.os.Parcelable
5 | import com.esotericsoftware.kryo.io.ByteBufferInput
6 | import com.esotericsoftware.kryo.io.ByteBufferOutput
7 |
8 | abstract class Serializable : Parcelable {
9 | abstract fun initializeDefaultValues()
10 | abstract fun serializeToBuffer(output: ByteBufferOutput)
11 | abstract fun deserializeFromBuffer(input: ByteBufferInput)
12 |
13 | override fun describeContents() = 0
14 |
15 | override fun writeToParcel(dest: Parcel, flags: Int) {
16 | dest.writeByteArray(KryoConverters.serialize(this))
17 | }
18 |
19 | abstract class CREATOR : Parcelable.Creator {
20 | abstract fun newInstance(): T
21 |
22 | override fun createFromParcel(source: Parcel): T {
23 | return KryoConverters.deserialize(newInstance(), source.createByteArray())
24 | }
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_add_entity.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_empty_route.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/ui/LongClickMenuPreference.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.ui
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.preference.PreferenceViewHolder
7 | import io.nekohasekai.sagernet.R
8 |
9 | class LongClickMenuPreference
10 | @JvmOverloads constructor(
11 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
12 | ) : SimpleMenuPreference(context, attrs, defStyle, 0) {
13 | private var mLongClickListener: View.OnLongClickListener? = null
14 |
15 | override fun onBindViewHolder(holder: PreferenceViewHolder) {
16 | super.onBindViewHolder(holder)
17 | val itemView: View = holder.itemView
18 | itemView.setOnLongClickListener {
19 | mLongClickListener?.onLongClick(it) ?: true
20 | }
21 | }
22 |
23 | fun setOnLongClickListener(longClickListener: View.OnLongClickListener) {
24 | this.mLongClickListener = longClickListener
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_app_placeholder.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/TempDatabase.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a
2 |
3 | import androidx.room.Database
4 | import androidx.room.Room
5 | import androidx.room.RoomDatabase
6 | import io.nekohasekai.sagernet.SagerNet
7 | import io.nekohasekai.sagernet.database.preference.KeyValuePair
8 | import kotlinx.coroutines.GlobalScope
9 | import kotlinx.coroutines.launch
10 |
11 | @Database(entities = [KeyValuePair::class], version = 1)
12 | abstract class TempDatabase : RoomDatabase() {
13 |
14 | companion object {
15 | @Suppress("EXPERIMENTAL_API_USAGE")
16 | private val instance by lazy {
17 | Room.inMemoryDatabaseBuilder(SagerNet.application, TempDatabase::class.java)
18 | .allowMainThreadQueries()
19 | .fallbackToDestructiveMigration()
20 | .setQueryExecutor { GlobalScope.launch { it.run() } }
21 | .build()
22 | }
23 |
24 | val profileCacheDao get() = instance.profileCacheDao()
25 |
26 | }
27 |
28 | abstract fun profileCacheDao(): KeyValuePair.Dao
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/widget/GroupPreference.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.widget
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import io.nekohasekai.sagernet.R
6 | import io.nekohasekai.sagernet.database.SagerDatabase
7 | import moe.matsuri.nb4a.ui.SimpleMenuPreference
8 |
9 | class GroupPreference
10 | @JvmOverloads constructor(
11 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
12 | ) : SimpleMenuPreference(context, attrs, defStyle, 0) {
13 |
14 | init {
15 | val groups = SagerDatabase.groupDao.allGroups()
16 |
17 | entries = groups.map { it.displayName() }.toTypedArray()
18 | entryValues = groups.map { "${it.id}" }.toTypedArray()
19 | }
20 |
21 | override fun getSummary(): CharSequence? {
22 | if (!value.isNullOrBlank() && value != "0") {
23 | return SagerDatabase.groupDao.getById(value.toLong())?.displayName()
24 | ?: super.getSummary()
25 | }
26 | return super.getSummary()
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/ui/LongClickListPreference.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.ui
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.preference.ListPreference
7 | import androidx.preference.PreferenceViewHolder
8 | import io.nekohasekai.sagernet.R
9 |
10 | class LongClickListPreference
11 | @JvmOverloads constructor(
12 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
13 | ) : ListPreference(context, attrs, defStyle, 0) {
14 | private var mLongClickListener: View.OnLongClickListener? = null
15 |
16 | override fun onBindViewHolder(holder: PreferenceViewHolder) {
17 | super.onBindViewHolder(holder)
18 | val itemView: View = holder.itemView
19 | itemView.setOnLongClickListener {
20 | mLongClickListener?.onLongClick(it) ?: true
21 | }
22 | }
23 |
24 | fun setOnLongClickListener(longClickListener: View.OnLongClickListener) {
25 | this.mLongClickListener = longClickListener
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_shutter_speed_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/ToolbarFragment.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.os.Bundle
4 | import android.view.KeyEvent
5 | import android.view.View
6 | import androidx.appcompat.widget.Toolbar
7 | import androidx.core.view.GravityCompat
8 | import androidx.fragment.app.Fragment
9 | import io.nekohasekai.sagernet.R
10 |
11 | open class ToolbarFragment : Fragment {
12 |
13 | constructor() : super()
14 | constructor(contentLayoutId: Int) : super(contentLayoutId)
15 |
16 | lateinit var toolbar: Toolbar
17 |
18 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
19 | super.onViewCreated(view, savedInstanceState)
20 | toolbar = view.findViewById(R.id.toolbar)
21 | toolbar.setNavigationIcon(R.drawable.ic_navigation_menu)
22 | toolbar.setNavigationOnClickListener {
23 | (activity as MainActivity).binding.drawerLayout.openDrawer(GravityCompat.START)
24 | }
25 | }
26 |
27 | open fun onKeyDown(ketCode: Int, event: KeyEvent) = false
28 | open fun onBackPressed(): Boolean = false
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nome do grupo
4 | Desagrupado
5 | Documento
6 | Tema
7 | Sobre
8 | Grupo
9 | Configuração
10 | Exportar informações de depuração
11 | Versão (%s)
12 | Versão
13 | Licenças de código aberto
14 | Canal de atualização do telegram
15 | Código fonte
16 | Projeto
17 | Um conjunto de ferramentas de proxy universal para Android, escrito em Kotlin.
18 | Link de inscrição
19 | Atualizar
20 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/gson/GsonConverters.java:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt.gson;
2 |
3 | import androidx.room.TypeConverter;
4 |
5 | import java.util.Collection;
6 | import java.util.List;
7 | import java.util.Set;
8 |
9 | import kotlin.collections.CollectionsKt;
10 | import kotlin.collections.SetsKt;
11 | import moe.matsuri.nb4a.utils.JavaUtil;
12 |
13 | public class GsonConverters {
14 |
15 | @TypeConverter
16 | public static String toJson(Object value) {
17 | if (value instanceof Collection) {
18 | if (((Collection>) value).isEmpty()) return "";
19 | }
20 | return JavaUtil.gson.toJson(value);
21 | }
22 |
23 | @TypeConverter
24 | public static List toList(String value) {
25 | if (JavaUtil.isNullOrBlank(value)) return CollectionsKt.listOf();
26 | return JavaUtil.gson.fromJson(value, List.class);
27 | }
28 |
29 | @TypeConverter
30 | public static Set toSet(String value) {
31 | if (JavaUtil.isNullOrBlank(value)) return SetsKt.setOf();
32 | return JavaUtil.gson.fromJson(value, Set.class);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_scanner.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
15 |
16 |
20 |
21 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/traffic_item_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/shortcuts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
12 |
13 |
18 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_progress_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
21 |
22 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/simple_menu_dropdown_item.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/TypeMap.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt
2 |
3 | import io.nekohasekai.sagernet.database.ProxyEntity
4 |
5 | object TypeMap : HashMap() {
6 | init {
7 | this["socks"] = ProxyEntity.TYPE_SOCKS
8 | this["http"] = ProxyEntity.TYPE_HTTP
9 | this["ss"] = ProxyEntity.TYPE_SS
10 | this["vmess"] = ProxyEntity.TYPE_VMESS
11 | this["trojan"] = ProxyEntity.TYPE_TROJAN
12 | this["trojan-go"] = ProxyEntity.TYPE_TROJAN_GO
13 | this["mieru"] = ProxyEntity.TYPE_MIERU
14 | this["naive"] = ProxyEntity.TYPE_NAIVE
15 | this["hysteria"] = ProxyEntity.TYPE_HYSTERIA
16 | this["ssh"] = ProxyEntity.TYPE_SSH
17 | this["wg"] = ProxyEntity.TYPE_WG
18 | this["tuic"] = ProxyEntity.TYPE_TUIC
19 | this["anytls"] = ProxyEntity.TYPE_ANYTLS
20 | this["neko"] = ProxyEntity.TYPE_NEKO
21 | this["config"] = ProxyEntity.TYPE_CONFIG
22 | }
23 |
24 | val reversed = HashMap()
25 |
26 | init {
27 | TypeMap.forEach { (key, type) ->
28 | reversed[type] = key
29 | }
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ktx/Browsers.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ktx
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import androidx.browser.customtabs.CustomTabColorSchemeParams
6 | import androidx.browser.customtabs.CustomTabsIntent
7 | import io.nekohasekai.sagernet.R
8 |
9 | fun Context.launchCustomTab(link: String) {
10 | CustomTabsIntent.Builder().apply {
11 | setColorScheme(CustomTabsIntent.COLOR_SCHEME_SYSTEM)
12 | setColorSchemeParams(
13 | CustomTabsIntent.COLOR_SCHEME_LIGHT,
14 | CustomTabColorSchemeParams.Builder().apply {
15 | setToolbarColor(getColorAttr(R.attr.colorPrimary))
16 | }.build()
17 | )
18 | setColorSchemeParams(
19 | CustomTabsIntent.COLOR_SCHEME_DARK,
20 | CustomTabColorSchemeParams.Builder().apply {
21 | setToolbarColor(getColorAttr(R.attr.colorPrimary))
22 | }.build()
23 | )
24 | }.build().apply {
25 | if (intent.resolveActivity(packageManager) != null) {
26 | launchUrl(this@launchCustomTab, Uri.parse(link))
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.widget
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import io.nekohasekai.sagernet.R
6 | import io.nekohasekai.sagernet.database.DataStore
7 | import io.nekohasekai.sagernet.database.ProfileManager
8 | import moe.matsuri.nb4a.ui.SimpleMenuPreference
9 |
10 | class OutboundPreference
11 | @JvmOverloads constructor(
12 | context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
13 | ) : SimpleMenuPreference(context, attrs, defStyle, 0) {
14 |
15 | init {
16 | setEntries(R.array.outbound_entry)
17 | setEntryValues(R.array.outbound_value)
18 | }
19 |
20 | override fun getSummary(): CharSequence? {
21 | if (value == "3") {
22 | val routeOutbound = DataStore.profileCacheStore.getLong(key + "Long") ?: 0
23 | if (routeOutbound > 0) {
24 | ProfileManager.getProfile(routeOutbound)?.displayName()?.let {
25 | return it
26 | }
27 | }
28 | }
29 | return super.getSummary()
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/libcore/interface_monitor.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | import (
4 | tun "github.com/sagernet/sing-tun"
5 | "github.com/sagernet/sing/common/control"
6 | "github.com/sagernet/sing/common/x/list"
7 | )
8 |
9 | // wtf
10 |
11 | type interfaceMonitorStub struct{}
12 |
13 | func (s *interfaceMonitorStub) Start() error {
14 | return nil
15 | }
16 |
17 | func (s *interfaceMonitorStub) Close() error {
18 | return nil
19 | }
20 |
21 | func (s *interfaceMonitorStub) DefaultInterface() *control.Interface {
22 | return nil
23 | }
24 |
25 | func (s *interfaceMonitorStub) OverrideAndroidVPN() bool {
26 | return false
27 | }
28 |
29 | func (s *interfaceMonitorStub) AndroidVPNEnabled() bool {
30 | return false
31 | }
32 |
33 | func (s *interfaceMonitorStub) RegisterCallback(callback tun.DefaultInterfaceUpdateCallback) *list.Element[tun.DefaultInterfaceUpdateCallback] {
34 | return nil
35 | }
36 |
37 | func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
38 | }
39 |
40 | func (s *interfaceMonitorStub) RegisterMyInterface(interfaceName string) {
41 | }
42 |
43 | func (s *interfaceMonitorStub) MyInterface() string {
44 | return ""
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_stream_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/ui/ConnectionTestNotification.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.ui
2 |
3 | import android.content.Context
4 | import androidx.core.app.NotificationCompat
5 | import io.nekohasekai.sagernet.R
6 | import io.nekohasekai.sagernet.SagerNet
7 | import io.nekohasekai.sagernet.ktx.Logs
8 |
9 | class ConnectionTestNotification(val context: Context, val title: String) {
10 | private val channelId = "connection-test"
11 | private val notificationId = 1001
12 |
13 | fun updateNotification(progress: Int, max: Int, finished: Boolean) {
14 | try {
15 | if (finished) {
16 | SagerNet.notification.cancel(notificationId)
17 | return
18 | }
19 | val builder = NotificationCompat.Builder(context, channelId)
20 | .setSmallIcon(R.drawable.ic_service_active)
21 | .setContentTitle(title)
22 | .setOnlyAlertOnce(true)
23 | .setContentText("$progress / $max").setProgress(max, progress, false)
24 | SagerNet.notification.notify(notificationId, builder.build())
25 | } catch (e: Exception) {
26 | Logs.w(e)
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/group_action_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
10 |
13 |
14 |
15 | -
18 |
19 |
22 |
25 |
26 |
27 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_keyboard_key.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/bg/ProxyService.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.bg
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Service
5 | import android.content.Intent
6 | import android.os.PowerManager
7 | import io.nekohasekai.sagernet.SagerNet
8 |
9 | class ProxyService : Service(), BaseService.Interface {
10 | override val data = BaseService.Data(this)
11 | override val tag: String get() = "SagerNetProxyService"
12 | override fun createNotification(profileName: String): ServiceNotification =
13 | ServiceNotification(this, profileName, "service-proxy", true)
14 |
15 | override var wakeLock: PowerManager.WakeLock? = null
16 | override var upstreamInterfaceName: String? = null
17 |
18 | @SuppressLint("WakelockTimeout")
19 | override fun acquireWakeLock() {
20 | wakeLock = SagerNet.power.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "sagernet:proxy")
21 | .apply { acquire() }
22 | }
23 |
24 | override fun onBind(intent: Intent) = super.onBind(intent)
25 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int =
26 | super.onStartCommand(intent, flags, startId)
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/ProfileSelectActivity.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import io.nekohasekai.sagernet.R
6 | import io.nekohasekai.sagernet.database.ProxyEntity
7 |
8 | class ProfileSelectActivity : ThemedActivity(R.layout.layout_empty),
9 | ConfigurationFragment.SelectCallback {
10 |
11 | companion object {
12 | const val EXTRA_SELECTED = "selected"
13 | const val EXTRA_PROFILE_ID = "id"
14 | }
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 |
19 | val selected = intent.getParcelableExtra(EXTRA_SELECTED)
20 |
21 | supportFragmentManager.beginTransaction()
22 | .replace(
23 | R.id.fragment_holder,
24 | ConfigurationFragment(true, selected, R.string.select_profile)
25 | )
26 | .commitAllowingStateLoss()
27 | }
28 |
29 | override fun returnProfile(profileId: Long) {
30 | setResult(RESULT_OK, Intent().apply {
31 | putExtra(EXTRA_PROFILE_ID, profileId)
32 | })
33 | finish()
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/widget/FabProgressBehavior.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.widget
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.coordinatorlayout.widget.CoordinatorLayout
7 | import com.google.android.material.progressindicator.CircularProgressIndicator
8 |
9 | class FabProgressBehavior(context: Context, attrs: AttributeSet?) :
10 | CoordinatorLayout.Behavior(context, attrs) {
11 | override fun layoutDependsOn(
12 | parent: CoordinatorLayout,
13 | child: CircularProgressIndicator,
14 | dependency: View,
15 | ): Boolean {
16 | return dependency.id == (child.layoutParams as CoordinatorLayout.LayoutParams).anchorId
17 | }
18 |
19 | override fun onLayoutChild(
20 | parent: CoordinatorLayout, child: CircularProgressIndicator,
21 | layoutDirection: Int,
22 | ): Boolean {
23 | val size = parent.getDependencies(child).single().measuredHeight + child.trackThickness
24 | return if (child.indicatorSize != size) {
25 | child.indicatorSize = size
26 | true
27 | } else false
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/database/StringCollectionConverter.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.database
2 |
3 | import androidx.room.TypeConverter
4 |
5 | class StringCollectionConverter {
6 | companion object {
7 | const val SPLIT_FLAG = ","
8 |
9 | /*
10 | @TypeConverter
11 | @JvmStatic
12 | fun fromList(list: List): String = if (list.isEmpty()) {
13 | ""
14 | } else {
15 | list.joinToString(SPLIT_FLAG)
16 | }
17 |
18 | @TypeConverter
19 | @JvmStatic
20 | fun toList(str: String): List = if (str.isBlank()) {
21 | emptyList()
22 | } else {
23 | str.split(SPLIT_FLAG)
24 | }
25 | */
26 |
27 |
28 | @TypeConverter
29 | @JvmStatic
30 | fun fromSet(set: Set): String = if (set.isEmpty()) {
31 | ""
32 | } else {
33 | set.joinToString(SPLIT_FLAG)
34 | }
35 |
36 | @TypeConverter
37 | @JvmStatic
38 | fun toSet(str: String): Set = if (str.isBlank()) {
39 | emptySet()
40 | } else {
41 | str.split(",").toSet()
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_settings.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/ui/LongClickSwitchPreference.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.ui
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.core.content.res.TypedArrayUtils
7 | import androidx.preference.PreferenceViewHolder
8 | import androidx.preference.R
9 | import androidx.preference.SwitchPreference
10 |
11 | class LongClickSwitchPreference
12 | @JvmOverloads constructor(
13 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = TypedArrayUtils.getAttr(
14 | context, R.attr.switchPreferenceStyle, android.R.attr.switchPreferenceStyle
15 | ), defStyleRes: Int = 0
16 | ) : SwitchPreference(
17 | context, attrs, defStyleAttr, defStyleRes
18 | ) {
19 | private var mLongClickListener: View.OnLongClickListener? = null
20 |
21 | override fun onBindViewHolder(holder: PreferenceViewHolder) {
22 | super.onBindViewHolder(holder)
23 | val itemView: View = holder.itemView
24 | itemView.setOnLongClickListener {
25 | mLongClickListener?.onLongClick(it) ?: true
26 | }
27 | }
28 |
29 | fun setOnLongClickListener(longClickListener: View.OnLongClickListener) {
30 | this.mLongClickListener = longClickListener
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/SwitchActivity.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.os.Bundle
4 | import io.nekohasekai.sagernet.R
5 | import io.nekohasekai.sagernet.SagerNet
6 | import io.nekohasekai.sagernet.database.DataStore
7 | import io.nekohasekai.sagernet.database.ProfileManager
8 | import io.nekohasekai.sagernet.ktx.runOnMainDispatcher
9 |
10 | class SwitchActivity : ThemedActivity(R.layout.layout_empty),
11 | ConfigurationFragment.SelectCallback {
12 |
13 | override val isDialog = true
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 |
18 | supportFragmentManager.beginTransaction()
19 | .replace(
20 | R.id.fragment_holder,
21 | ConfigurationFragment(true, null, R.string.action_switch)
22 | )
23 | .commitAllowingStateLoss()
24 | }
25 |
26 | override fun returnProfile(profileId: Long) {
27 | val old = DataStore.selectedProxy
28 | DataStore.selectedProxy = profileId
29 | runOnMainDispatcher {
30 | ProfileManager.postUpdate(old, true)
31 | ProfileManager.postUpdate(profileId, true)
32 | }
33 | SagerNet.reloadService()
34 | finish()
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_service_connected.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_service_stopping.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/profile_config_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
10 |
16 |
20 |
24 |
28 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.database.preference
2 |
3 | import androidx.room.Database
4 | import androidx.room.Room
5 | import androidx.room.RoomDatabase
6 | import dev.matrix.roomigrant.GenerateRoomMigrations
7 | import io.nekohasekai.sagernet.Key
8 | import io.nekohasekai.sagernet.SagerNet
9 | import kotlinx.coroutines.GlobalScope
10 | import kotlinx.coroutines.launch
11 |
12 | @Database(entities = [KeyValuePair::class], version = 1)
13 | @GenerateRoomMigrations
14 | abstract class PublicDatabase : RoomDatabase() {
15 | companion object {
16 | val instance by lazy {
17 | SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs()
18 | Room.databaseBuilder(SagerNet.application, PublicDatabase::class.java, Key.DB_PUBLIC)
19 | .setJournalMode(JournalMode.TRUNCATE)
20 | .allowMainThreadQueries()
21 | .enableMultiInstanceInvalidation()
22 | .fallbackToDestructiveMigration()
23 | .setQueryExecutor { GlobalScope.launch { it.run() } }
24 | .build()
25 | }
26 |
27 | val kvPairDao get() = instance.keyValuePairDao()
28 | }
29 |
30 | abstract fun keyValuePairDao(): KeyValuePair.Dao
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/balancer_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
17 |
18 |
25 |
26 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_group.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
16 |
17 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_route.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
16 |
17 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_copyright.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_assets.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
18 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 | # Gradle parallel build
23 | org.gradle.parallel=true
24 | android.nonTransitiveRClass=false
25 | android.nonFinalResIds=false
26 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/VMessBean.java:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt.v2ray;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | import io.nekohasekai.sagernet.fmt.KryoConverters;
8 | import moe.matsuri.nb4a.utils.JavaUtil;
9 |
10 | public class VMessBean extends StandardV2RayBean {
11 |
12 | public Integer alterId; // alterID == -1 --> VLESS
13 |
14 | @Override
15 | public void initializeDefaultValues() {
16 | super.initializeDefaultValues();
17 |
18 | alterId = alterId != null ? alterId : 0;
19 |
20 | if (alterId == -1) {
21 | encryption = JavaUtil.isNotBlank(encryption) ? encryption : "";
22 | } else {
23 | encryption = JavaUtil.isNotBlank(encryption) ? encryption : "auto";
24 | }
25 | }
26 |
27 | @NotNull
28 | @Override
29 | public VMessBean clone() {
30 | return KryoConverters.deserialize(new VMessBean(), KryoConverters.serialize(this));
31 | }
32 |
33 | public static final Creator CREATOR = new CREATOR() {
34 | @NonNull
35 | @Override
36 | public VMessBean newInstance() {
37 | return new VMessBean();
38 | }
39 |
40 | @Override
41 | public VMessBean[] newArray(int size) {
42 | return new VMessBean[size];
43 | }
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/widget/AutoCollapseTextView.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.widget
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.graphics.Rect
6 | import android.util.AttributeSet
7 | import android.view.MotionEvent
8 | import androidx.appcompat.widget.AppCompatTextView
9 | import androidx.core.view.isGone
10 |
11 | class AutoCollapseTextView @JvmOverloads constructor(
12 | context: Context, attrs: AttributeSet? = null,
13 | defStyleAttr: Int = 0,
14 | ) :
15 | AppCompatTextView(context, attrs, defStyleAttr) {
16 | override fun onTextChanged(
17 | text: CharSequence?,
18 | start: Int,
19 | lengthBefore: Int,
20 | lengthAfter: Int,
21 | ) {
22 | super.onTextChanged(text, start, lengthBefore, lengthAfter)
23 | isGone = text.isNullOrEmpty()
24 | }
25 |
26 | // #1874
27 | override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) =
28 | try {
29 | super.onFocusChanged(focused, direction, previouslyFocusedRect)
30 | } catch (e: IndexOutOfBoundsException) {
31 | }
32 |
33 | @SuppressLint("ClickableViewAccessibility")
34 | override fun onTouchEvent(event: MotionEvent?) = try {
35 | super.onTouchEvent(event)
36 | } catch (e: IndexOutOfBoundsException) {
37 | false
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_logcat.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
18 |
19 |
23 |
24 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/ui/Dialogs.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.ui
2 |
3 | import android.content.Context
4 | import android.widget.TextView
5 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
6 | import io.nekohasekai.sagernet.R
7 | import io.nekohasekai.sagernet.ktx.Logs
8 | import io.nekohasekai.sagernet.ktx.readableMessage
9 | import io.nekohasekai.sagernet.ktx.runOnMainDispatcher
10 |
11 | object Dialogs {
12 | fun logExceptionAndShow(context: Context, e: Exception, callback: Runnable) {
13 | Logs.e(e)
14 | runOnMainDispatcher {
15 | MaterialAlertDialogBuilder(context)
16 | .setTitle(R.string.error_title)
17 | .setMessage(e.readableMessage)
18 | .setCancelable(false)
19 | .setPositiveButton(android.R.string.ok) { _, _ ->
20 | callback.run()
21 | }
22 | .show()
23 | }
24 | }
25 |
26 | fun message(context: Context, title: String, message: String) {
27 | runOnMainDispatcher {
28 | val dialog = MaterialAlertDialogBuilder(context)
29 | .setTitle(title)
30 | .setMessage(message)
31 | .setCancelable(true)
32 | .show()
33 | dialog.findViewById(android.R.id.message)?.apply {
34 | setTextIsSelectable(true)
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/moe/matsuri/nb4a/utils/WebViewUtil.kt:
--------------------------------------------------------------------------------
1 | package moe.matsuri.nb4a.utils
2 |
3 | import android.os.Build
4 | import android.webkit.WebResourceError
5 | import android.webkit.WebResourceRequest
6 | import android.webkit.WebResourceResponse
7 | import android.webkit.WebView
8 | import io.nekohasekai.sagernet.ktx.Logs
9 | import java.io.ByteArrayInputStream
10 | import java.io.InputStream
11 |
12 | object WebViewUtil {
13 | fun onReceivedError(
14 | view: WebView?, request: WebResourceRequest?, error: WebResourceError?
15 | ) {
16 | if (Build.VERSION.SDK_INT >= 23 && error != null) {
17 | Logs.e("WebView error description: ${error.description}")
18 | }
19 | Logs.e("WebView error: ${error.toString()}")
20 | }
21 |
22 | fun interceptRequest(
23 | res: (String) -> InputStream?, view: WebView?, request: WebResourceRequest?
24 | ): WebResourceResponse {
25 | val path = request?.url?.path ?: "404"
26 | val input = res(path)
27 | var mime = "text/plain"
28 | if (path.endsWith(".js")) mime = "application/javascript"
29 | if (path.endsWith(".html")) mime = "text/html"
30 | return if (input != null) {
31 | WebResourceResponse(mime, "UTF-8", input)
32 | } else {
33 | WebResourceResponse(
34 | "text/plain", "UTF-8", ByteArrayInputStream("".toByteArray())
35 | )
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_tools.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
29 |
30 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/UniversalFmt.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt
2 |
3 | import io.nekohasekai.sagernet.database.ProxyEntity
4 | import io.nekohasekai.sagernet.database.ProxyGroup
5 | import moe.matsuri.nb4a.utils.Util
6 |
7 | fun parseUniversal(link: String): AbstractBean {
8 | return if (link.contains("?")) {
9 | val type = link.substringAfter("sn://").substringBefore("?")
10 | ProxyEntity(type = TypeMap[type] ?: error("Type $type not found")).apply {
11 | putByteArray(Util.zlibDecompress(Util.b64Decode(link.substringAfter("?"))))
12 | }.requireBean()
13 | } else {
14 | val type = link.substringAfter("sn://").substringBefore(":")
15 | ProxyEntity(type = TypeMap[type] ?: error("Type $type not found")).apply {
16 | putByteArray(Util.b64Decode(link.substringAfter(":").substringAfter(":")))
17 | }.requireBean()
18 | }
19 | }
20 |
21 | fun AbstractBean.toUniversalLink(): String {
22 | var link = "sn://"
23 | link += TypeMap.reversed[ProxyEntity().putBean(this).type]
24 | link += "?"
25 | link += Util.b64EncodeUrlSafe(Util.zlibCompress(KryoConverters.serialize(this), 9))
26 | return link
27 | }
28 |
29 |
30 | fun ProxyGroup.toUniversalLink(): String {
31 | var link = "sn://subscription?"
32 | export = true
33 | link += Util.b64EncodeUrlSafe(Util.zlibCompress(KryoConverters.serialize(this), 9))
34 | export = false
35 | return link
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.ui
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.viewpager2.adapter.FragmentStateAdapter
7 | import com.google.android.material.tabs.TabLayoutMediator
8 | import io.nekohasekai.sagernet.R
9 | import io.nekohasekai.sagernet.databinding.LayoutToolsBinding
10 |
11 | class ToolsFragment : ToolbarFragment(R.layout.layout_tools) {
12 |
13 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
14 | super.onViewCreated(view, savedInstanceState)
15 | toolbar.setTitle(R.string.menu_tools)
16 |
17 | val tools = mutableListOf()
18 | tools.add(NetworkFragment())
19 | tools.add(BackupFragment())
20 |
21 | val binding = LayoutToolsBinding.bind(view)
22 | binding.toolsPager.adapter = ToolsAdapter(tools)
23 |
24 | TabLayoutMediator(binding.toolsTab, binding.toolsPager) { tab, position ->
25 | tab.text = tools[position].name()
26 | tab.view.setOnLongClickListener { // clear toast
27 | true
28 | }
29 | }.attach()
30 | }
31 |
32 | inner class ToolsAdapter(val tools: List) : FragmentStateAdapter(this) {
33 |
34 | override fun getItemCount() = tools.size
35 |
36 | override fun createFragment(position: Int) = tools[position]
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/libcore/stun.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "libcore/stun"
8 | )
9 |
10 | type StunResult struct {
11 | Text string
12 | Success bool
13 | }
14 |
15 | func StunTest(server string) *StunResult {
16 | //note: this library doesn't support stun1.l.google.com:19302
17 | ret := &StunResult{}
18 | var text string
19 |
20 | // Old NAT Type Test
21 | client := stun.NewClient()
22 | client.SetServerAddr(server)
23 | nat, host, err, fakeFullCone := client.Discover()
24 | if err != nil {
25 | text += fmt.Sprintln("Discover Error:", err.Error())
26 | }
27 |
28 | if fakeFullCone {
29 | text += fmt.Sprintln("Fake fullcone (no endpoint IP change) detected!!")
30 | }
31 |
32 | if host != nil {
33 | text += fmt.Sprintln("NAT Type:", nat)
34 | text += fmt.Sprintln("External IP Family:", host.Family())
35 | text += fmt.Sprintln("External IP:", host.IP())
36 | text += fmt.Sprintln("External Port:", host.Port())
37 | }
38 |
39 | // New NAT Test
40 |
41 | natBehavior, err := client.BehaviorTest()
42 | if err != nil {
43 | text += fmt.Sprintln("BehaviorTest Error:", err.Error())
44 | }
45 |
46 | if natBehavior != nil {
47 | text += fmt.Sprintln("Mapping Behavior:", natBehavior.MappingType)
48 | text += fmt.Sprintln("Filtering Behavior:", natBehavior.FilteringType)
49 | text += fmt.Sprintln("Normal NAT Type:", natBehavior.NormalType())
50 | }
51 |
52 | ret.Success = true
53 | ret.Text = strings.TrimRight(text, "\n")
54 | return ret
55 | }
56 |
--------------------------------------------------------------------------------
/app/schemas/moe.matsuri.nb4a.TempDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "f1aab1fb633378621635c344dbc8ac7b",
6 | "entities": [
7 | {
8 | "tableName": "KeyValuePair",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
10 | "fields": [
11 | {
12 | "fieldPath": "key",
13 | "columnName": "key",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "valueType",
19 | "columnName": "valueType",
20 | "affinity": "INTEGER",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "value",
25 | "columnName": "value",
26 | "affinity": "BLOB",
27 | "notNull": true
28 | }
29 | ],
30 | "primaryKey": {
31 | "columnNames": [
32 | "key"
33 | ],
34 | "autoGenerate": false
35 | },
36 | "indices": [],
37 | "foreignKeys": []
38 | }
39 | ],
40 | "views": [],
41 | "setupQueries": [
42 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
43 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1aab1fb633378621635c344dbc8ac7b')"
44 | ]
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_group_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
30 |
31 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/java/io/nekohasekai/sagernet/fmt/http/HttpFmt.kt:
--------------------------------------------------------------------------------
1 | package io.nekohasekai.sagernet.fmt.http
2 |
3 | import io.nekohasekai.sagernet.fmt.v2ray.isTLS
4 | import io.nekohasekai.sagernet.fmt.v2ray.setTLS
5 | import io.nekohasekai.sagernet.ktx.urlSafe
6 | import okhttp3.HttpUrl
7 | import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
8 |
9 | fun parseHttp(link: String): HttpBean {
10 | val httpUrl = link.toHttpUrlOrNull() ?: error("Invalid http(s) link: $link")
11 |
12 | if (httpUrl.encodedPath != "/") error("Not http proxy")
13 |
14 | return HttpBean().apply {
15 | serverAddress = httpUrl.host
16 | serverPort = httpUrl.port
17 | username = httpUrl.username
18 | password = httpUrl.password
19 | sni = httpUrl.queryParameter("sni")
20 | name = httpUrl.fragment
21 | setTLS(httpUrl.scheme == "https")
22 | }
23 | }
24 |
25 | fun HttpBean.toUri(): String {
26 | val builder = HttpUrl.Builder().scheme(if (isTLS()) "https" else "http").host(serverAddress)
27 |
28 | if (serverPort in 1..65535) {
29 | builder.port(serverPort)
30 | }
31 |
32 | if (username.isNotBlank()) {
33 | builder.username(username)
34 | }
35 | if (password.isNotBlank()) {
36 | builder.password(password)
37 | }
38 | if (sni.isNotBlank()) {
39 | builder.addQueryParameter("sni", sni)
40 | }
41 | if (name.isNotBlank()) {
42 | builder.encodedFragment(name.urlSafe())
43 | }
44 |
45 | return builder.toString()
46 | }
--------------------------------------------------------------------------------
/app/schemas/io.nekohasekai.sagernet.database.preference.PublicDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "f1aab1fb633378621635c344dbc8ac7b",
6 | "entities": [
7 | {
8 | "tableName": "KeyValuePair",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
10 | "fields": [
11 | {
12 | "fieldPath": "key",
13 | "columnName": "key",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "valueType",
19 | "columnName": "valueType",
20 | "affinity": "INTEGER",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "value",
25 | "columnName": "value",
26 | "affinity": "BLOB",
27 | "notNull": true
28 | }
29 | ],
30 | "primaryKey": {
31 | "columnNames": [
32 | "key"
33 | ],
34 | "autoGenerate": false
35 | },
36 | "indices": [],
37 | "foreignKeys": []
38 | }
39 | ],
40 | "views": [],
41 | "setupQueries": [
42 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
43 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1aab1fb633378621635c344dbc8ac7b')"
44 | ]
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/profile_share_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
10 |
13 |
14 |
15 | -
18 |
19 |
22 |
25 |
26 |
27 | -
31 |
32 |
35 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/libcore/geosite.go:
--------------------------------------------------------------------------------
1 | package libcore
2 |
3 | import (
4 | "fmt"
5 | "path/filepath"
6 |
7 | geosites "github.com/sagernet/sing-box/common/geosite"
8 | C "github.com/sagernet/sing-box/constant"
9 | "github.com/sagernet/sing-box/nekoutils"
10 | "github.com/sagernet/sing-box/option"
11 | )
12 |
13 | type geosite struct {
14 | geositeReader *geosites.Reader
15 | }
16 |
17 | func (g *geosite) Open(path string) error {
18 | geositeReader, _, err := geosites.Open(path)
19 | g.geositeReader = geositeReader
20 | return err
21 | }
22 |
23 | func (g *geosite) Rules(code string) ([]option.HeadlessRule, error) {
24 | sourceSet, err := g.geositeReader.Read(code)
25 | if err != nil {
26 | return nil, fmt.Errorf("failed to read geosite code %s :%w", code, err)
27 | }
28 |
29 | var headlessRule option.DefaultHeadlessRule
30 |
31 | defaultRule := geosites.Compile(sourceSet)
32 |
33 | headlessRule.Domain = defaultRule.Domain
34 | headlessRule.DomainSuffix = defaultRule.DomainSuffix
35 | headlessRule.DomainKeyword = defaultRule.DomainKeyword
36 | headlessRule.DomainRegex = defaultRule.DomainRegex
37 |
38 | return []option.HeadlessRule{
39 | {
40 | Type: C.RuleTypeDefault,
41 | DefaultOptions: headlessRule,
42 | },
43 | }, nil
44 | }
45 |
46 | func init() {
47 | nekoutils.GetGeoSiteHeadlessRules = func(name string) ([]option.HeadlessRule, error) {
48 | g := new(geosite)
49 | if err := g.Open(filepath.Join(externalAssetsPath, "geosite.db")); err != nil {
50 | return nil, err
51 | }
52 | return g.Rules(name)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------