mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-21 02:01:03 +07:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f5e42dd61 | |||
| a983d0504e | |||
| d0b8535395 | |||
| f84480cf56 | |||
| de7a026ec1 | |||
| a128c7d247 | |||
| f316f0e25a | |||
| ea5242e29b | |||
| b31a62c55f | |||
| 02e3107a23 | |||
| 1862850108 | |||
| f73792844c | |||
| a7199ca6f5 | |||
| 5e757cdd3b | |||
| 92af1f3268 | |||
| aad9d6dae2 | |||
| 423fe3fd4f |
@@ -10,10 +10,10 @@ env:
|
||||
|
||||
jobs:
|
||||
Build-Linux-Ubuntu:
|
||||
runs-on: 4-core
|
||||
runs-on: android-runner
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.8.3
|
||||
QT_VERSION: 6.10.1
|
||||
QIF_VERSION: 4.7
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
sudo apt-get install libxkbcommon-x11-0
|
||||
sudo apt-get install libxkbcommon-x11-0 libsecret-1-dev
|
||||
export QT_BIN_DIR=${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/gcc_64/bin
|
||||
export QIF_BIN_DIR=${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin
|
||||
bash deploy/build_linux.sh
|
||||
@@ -537,7 +537,7 @@ jobs:
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-Android:
|
||||
runs-on: 4-core
|
||||
runs-on: android-runner
|
||||
|
||||
env:
|
||||
ANDROID_BUILD_PLATFORM: android-36
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Verify git tag
|
||||
run: |
|
||||
TAG_NAME=${{ inputs.RELEASE_VERSION }}
|
||||
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
|
||||
CMAKE_TAG=$(grep 'set(AMNEZIAVPN_VERSION' CMakeLists.txt | sed -E 's/.*AMNEZIAVPN_VERSION ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1/')
|
||||
if [[ "$TAG_NAME" == "$CMAKE_TAG" ]]; then
|
||||
echo "Git tag ($TAG_NAME) matches CMakeLists.txt version ($CMAKE_TAG)."
|
||||
else
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
set(AMNEZIAVPN_VERSION 4.8.12.8)
|
||||
set(AMNEZIAVPN_VERSION 4.8.12.9)
|
||||
|
||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
@@ -12,7 +12,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(APP_ANDROID_VERSION_CODE 2104)
|
||||
set(APP_ANDROID_VERSION_CODE 2105)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
|
||||
+1
-1
Submodule client/3rd-prebuilt updated: adf5eb920f...579673b2ed
@@ -1,7 +1,10 @@
|
||||
package org.amnezia.vpn
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -11,7 +14,25 @@ private const val TAG = "TvFilePicker"
|
||||
|
||||
class TvFilePicker : ComponentActivity() {
|
||||
|
||||
private val fileChooseResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) {
|
||||
private val fileChooseResultLauncher = registerForActivityResult(object : ActivityResultContracts.OpenDocument() {
|
||||
override fun createIntent(context: Context, input: Array<String>): Intent {
|
||||
val intent = super.createIntent(context, input)
|
||||
|
||||
val activitiesToResolveIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong()))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
context.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
|
||||
}
|
||||
if (activitiesToResolveIntent.all {
|
||||
val name = it.activityInfo.packageName
|
||||
name.startsWith("com.google.android.tv.frameworkpackagestubs") || name.startsWith("com.android.tv.frameworkpackagestubs")
|
||||
}) {
|
||||
throw ActivityNotFoundException()
|
||||
}
|
||||
return intent
|
||||
}
|
||||
}) {
|
||||
setResult(RESULT_OK, Intent().apply { data = it })
|
||||
finish()
|
||||
}
|
||||
@@ -31,7 +52,7 @@ class TvFilePicker : ComponentActivity() {
|
||||
private fun getFile() {
|
||||
try {
|
||||
Log.v(TAG, "getFile")
|
||||
fileChooseResultLauncher.launch("*/*")
|
||||
fileChooseResultLauncher.launch(arrayOf("*/*"))
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
Log.w(TAG, "Activity not found")
|
||||
setResult(RESULT_CANCELED, Intent().apply { putExtra("activityNotFound", true) })
|
||||
|
||||
@@ -419,6 +419,18 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
|
||||
qDebug().noquote() << "ServerController::installDockerWorker" << stdOut;
|
||||
if (container == DockerContainer::Awg2) {
|
||||
QRegularExpression regex(R"(Linux\s+(\d+)\.(\d+)[^\d]*)");
|
||||
QRegularExpressionMatch match = regex.match(stdOut);
|
||||
if (match.hasMatch()) {
|
||||
int majorVersion = match.captured(1).toInt();
|
||||
int minorVersion = match.captured(2).toInt();
|
||||
|
||||
if (majorVersion < 4 || (majorVersion == 4 && minorVersion < 14)) {
|
||||
return ErrorCode::ServerLinuxKernelTooOld;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stdOut.contains("lock"))
|
||||
return ErrorCode::ServerPacketManagerError;
|
||||
if (stdOut.contains("command not found"))
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace amnezia
|
||||
ServerDockerOnCgroupsV2 = 211,
|
||||
ServerCgroupMountpoint = 212,
|
||||
DockerPullRateLimit = 213,
|
||||
ServerLinuxKernelTooOld = 214,
|
||||
|
||||
// Ssh connection errors
|
||||
SshRequestDeniedError = 300,
|
||||
|
||||
@@ -29,6 +29,7 @@ QString errorString(ErrorCode code) {
|
||||
case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break;
|
||||
case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break;
|
||||
case(ErrorCode::DockerPullRateLimit): errorMessage = QObject::tr("Docker error: The pull rate limit has been reached"); break;
|
||||
case(ErrorCode::ServerLinuxKernelTooOld): errorMessage = QObject::tr("Server error: Linux kernel is too old"); break;
|
||||
|
||||
// Libssh errors
|
||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||
|
||||
@@ -21,4 +21,5 @@ if [ "$(systemctl is-active docker)" != "active" ]; then \
|
||||
sleep 5; sudo systemctl start docker; sleep 5;\
|
||||
fi;\
|
||||
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install sudo, command not found"; exit 1; fi;\
|
||||
docker --version
|
||||
docker --version;\
|
||||
uname -sr
|
||||
|
||||
@@ -94,6 +94,15 @@ public:
|
||||
setValue("Conf/startMinimized", enabled);
|
||||
}
|
||||
|
||||
bool isNewsNotifications() const
|
||||
{
|
||||
return value("Conf/newsNotifications", true).toBool();
|
||||
}
|
||||
void setNewsNotifications(bool enabled)
|
||||
{
|
||||
setValue("Conf/newsNotifications", enabled);
|
||||
}
|
||||
|
||||
bool isSaveLogs() const
|
||||
{
|
||||
return value("Conf/saveLogs", false).toBool();
|
||||
|
||||
@@ -308,6 +308,15 @@ void SettingsController::toggleStartMinimized(bool enable)
|
||||
emit startMinimizedChanged();
|
||||
}
|
||||
|
||||
bool SettingsController::isNewsNotificationsEnabled()
|
||||
{
|
||||
return m_settings->isNewsNotifications();
|
||||
}
|
||||
void SettingsController::toggleNewsNotificationsEnabled(bool enable)
|
||||
{
|
||||
m_settings->setNewsNotifications(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isScreenshotsEnabled()
|
||||
{
|
||||
return m_settings->isScreenshotsEnabled();
|
||||
|
||||
@@ -73,6 +73,9 @@ public slots:
|
||||
bool isStartMinimizedEnabled();
|
||||
void toggleStartMinimized(bool enable);
|
||||
|
||||
bool isNewsNotificationsEnabled();
|
||||
void toggleNewsNotificationsEnabled(bool enable);
|
||||
|
||||
bool isScreenshotsEnabled();
|
||||
void toggleScreenshotsEnabled(bool enable);
|
||||
|
||||
|
||||
@@ -49,6 +49,36 @@ Item {
|
||||
return drawerContent.state === stateName
|
||||
}
|
||||
|
||||
function findComponent(obj, typeCtor) {
|
||||
if (!obj)
|
||||
return null
|
||||
|
||||
if (obj instanceof typeCtor)
|
||||
return obj
|
||||
|
||||
if (obj.children && obj.children.length > 0) {
|
||||
for (var i = 0; i < obj.children.length; i++) {
|
||||
var matchingChildren = findComponent(obj.children[i], typeCtor)
|
||||
if (matchingChildren) return matchingChildren
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.contentItem) {
|
||||
var matchingContentItem = findComponent(obj.contentItem, typeCtor)
|
||||
if (matchingContentItem) return matchingContentItem
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function setParentInteractive(value) {
|
||||
var flickableType = findComponent(root.parent, Flickable)
|
||||
var listViewType = findComponent(root.parent, ListView)
|
||||
|
||||
if (flickableType) flickableType.interactive = value
|
||||
if (listViewType) listViewType.interactive = value
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Qt.application
|
||||
|
||||
@@ -93,6 +123,8 @@ Item {
|
||||
|
||||
aboutToHide()
|
||||
|
||||
setParentInteractive(true)
|
||||
|
||||
closed()
|
||||
}
|
||||
|
||||
@@ -118,6 +150,8 @@ Item {
|
||||
|
||||
root.aboutToShow()
|
||||
|
||||
setParentInteractive(false)
|
||||
|
||||
root.opened()
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ Item {
|
||||
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: root.enabled
|
||||
@@ -296,13 +298,13 @@ Item {
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
if (!rightImageSource && clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
if (!rightImageSource && clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,16 @@ PageType {
|
||||
ListElement { name : "aes-128-gcm" }
|
||||
}
|
||||
|
||||
function updateSelectedIndex() {
|
||||
cipherDropDown.text = cipher
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipher) {
|
||||
selectedIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
@@ -147,13 +157,14 @@ PageType {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
cipherDropDown.text = cipher
|
||||
updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||
selectedIndex = i
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: listView.model
|
||||
function onDataChanged() {
|
||||
cipherListView.updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,16 @@ PageType {
|
||||
ListElement { name : qsTr("SHA1") }
|
||||
}
|
||||
|
||||
function updateSelectedIndex() {
|
||||
hashDropDown.text = hash
|
||||
for (var i = 0; i < hashListView.model.count; i++) {
|
||||
if (hashListView.model.get(i).name === hash) {
|
||||
selectedIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
hashDropDown.text = selectedText
|
||||
hash = hashDropDown.text
|
||||
@@ -199,13 +209,14 @@ PageType {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
hashDropDown.text = hash
|
||||
updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < hashListView.model.count; i++) {
|
||||
if (hashListView.model.get(i).name === hashDropDown.text) {
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: listView.model
|
||||
function onDataChanged() {
|
||||
hashListView.updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,6 +253,16 @@ PageType {
|
||||
ListElement { name : qsTr("none") }
|
||||
}
|
||||
|
||||
function updateSelectedIndex() {
|
||||
cipherDropDown.text = cipher
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipher) {
|
||||
selectedIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
@@ -249,13 +270,14 @@ PageType {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
cipherDropDown.text = cipher
|
||||
updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: listView.model
|
||||
function onDataChanged() {
|
||||
cipherListView.updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,16 @@ PageType {
|
||||
ListElement { name : "aes-128-gcm" }
|
||||
}
|
||||
|
||||
function updateSelectedIndex() {
|
||||
cipherDropDown.text = cipher
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipher) {
|
||||
selectedIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
@@ -116,13 +126,14 @@ PageType {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
cipherDropDown.text = cipher
|
||||
updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: listView.model
|
||||
function onDataChanged() {
|
||||
cipherListView.updateSelectedIndex()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ PageType {
|
||||
id: news
|
||||
|
||||
property string title: qsTr("News & Notifications")
|
||||
readonly property string leftImagePath: NewsModel.hasUnread ? "qrc:/images/controls/news-unread.svg" : "qrc:/images/controls/news.svg"
|
||||
readonly property string leftImagePath: NewsModel.hasUnread && SettingsController.isNewsNotificationsEnabled() ? "qrc:/images/controls/news-unread.svg" : "qrc:/images/controls/news.svg"
|
||||
property bool isVisible: ServersModel.hasServersFromGatewayApi
|
||||
readonly property var clickedHandler: function() {
|
||||
if (!ServersModel.hasServersFromGatewayApi) {
|
||||
|
||||
@@ -168,6 +168,29 @@ PageType {
|
||||
DividerType {
|
||||
visible: !GC.isMobile()
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: switcherNewsNotificationEnabled
|
||||
|
||||
visible: ServersModel.hasServersFromGatewayApi
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
text: qsTr("News Notification")
|
||||
descriptionText: qsTr("Show notification icon when has unread news")
|
||||
|
||||
checked: SettingsController.isNewsNotificationsEnabled()
|
||||
onToggled: function() {
|
||||
if (checked !== SettingsController.isNewsNotificationsEnabled()) {
|
||||
SettingsController.toggleNewsNotificationsEnabled(checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: !GC.isMobile()
|
||||
}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
|
||||
@@ -107,6 +107,7 @@ PageType {
|
||||
|
||||
onClicked: function() {
|
||||
isEasySetup = true
|
||||
checked = true
|
||||
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
||||
|
||||
listView.dockerContainer = dockerContainer
|
||||
|
||||
@@ -383,7 +383,7 @@ PageType {
|
||||
objectName: "settingsTabButton"
|
||||
|
||||
isSelected: tabBar.currentIndex === 2
|
||||
image: (ServersModel.hasServersFromGatewayApi && NewsModel.hasUnread) ? "qrc:/images/controls/settings-news.svg" : "qrc:/images/controls/settings.svg"
|
||||
image: (ServersModel.hasServersFromGatewayApi && NewsModel.hasUnread && SettingsController.isNewsNotificationsEnabled()) ? "qrc:/images/controls/settings-news.svg" : "qrc:/images/controls/settings.svg"
|
||||
Binding {
|
||||
target: settingsTabButton
|
||||
property: "defaultColor"
|
||||
|
||||
@@ -499,7 +499,7 @@ bool VpnConnection::startNetworkCheckIfReady()
|
||||
|
||||
return IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
QRemoteObjectPendingReply<bool> reply = iface->startNetworkCheck(gateway, localAddress);
|
||||
return reply.waitForFinished() && reply.returnValue();
|
||||
return reply.waitForFinished(1000) && reply.returnValue();
|
||||
});
|
||||
#else
|
||||
return false;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
</array>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>Sockets</key>
|
||||
<dict>
|
||||
<key>Listeners</key>
|
||||
|
||||
@@ -7,42 +7,54 @@ LOG_FOLDER=/var/log/$APP_NAME
|
||||
LOG_FILE="$LOG_FOLDER/post-install.log"
|
||||
APP_PATH=/Applications/$APP_NAME.app
|
||||
|
||||
rm -rf "$LOG_FOLDER"
|
||||
mkdir -p "$LOG_FOLDER"
|
||||
echo "`date` Script started" > "$LOG_FILE"
|
||||
|
||||
log() {
|
||||
echo "`date` $*" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
run_cmd() {
|
||||
log "CMD: $*"
|
||||
"$@" >> "$LOG_FILE" 2>&1
|
||||
local ec=$?
|
||||
log "EXIT: $ec"
|
||||
return $ec
|
||||
}
|
||||
|
||||
# Handle new installations unpacked into localized folder
|
||||
if [ -d "/Applications/${APP_NAME}.localized" ]; then
|
||||
echo "`date` Detected ${APP_NAME}.localized, migrating to standard path" >> $LOG_FILE
|
||||
sudo rm -rf "$APP_PATH"
|
||||
sudo mv "/Applications/${APP_NAME}.localized/${APP_NAME}.app" "$APP_PATH"
|
||||
sudo rm -rf "/Applications/${APP_NAME}.localized"
|
||||
log "Detected ${APP_NAME}.localized, migrating to standard path"
|
||||
run_cmd sudo rm -rf "$APP_PATH"
|
||||
run_cmd sudo mv "/Applications/${APP_NAME}.localized/${APP_NAME}.app" "$APP_PATH"
|
||||
run_cmd sudo rm -rf "/Applications/${APP_NAME}.localized"
|
||||
fi
|
||||
|
||||
if launchctl list "$APP_NAME-service" &> /dev/null; then
|
||||
launchctl unload "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
rm -f "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
fi
|
||||
run_cmd launchctl bootout system "$LAUNCH_DAEMONS_PLIST_NAME" || run_cmd launchctl unload "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
run_cmd rm -f "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
|
||||
sudo chmod -R a-w "$APP_PATH/"
|
||||
sudo chown -R root "$APP_PATH/"
|
||||
sudo chgrp -R wheel "$APP_PATH/"
|
||||
run_cmd sudo chmod -R a-w "$APP_PATH/"
|
||||
run_cmd sudo chown -R root "$APP_PATH/"
|
||||
run_cmd sudo chgrp -R wheel "$APP_PATH/"
|
||||
|
||||
rm -rf $LOG_FOLDER
|
||||
mkdir -p $LOG_FOLDER
|
||||
|
||||
echo "`date` Script started" > $LOG_FILE
|
||||
|
||||
echo "Requesting ${APP_NAME} to quit gracefully" >> "$LOG_FILE"
|
||||
osascript -e 'tell application "AmneziaVPN" to quit'
|
||||
log "Requesting ${APP_NAME} to quit gracefully"
|
||||
run_cmd osascript -e 'tell application "AmneziaVPN" to quit' || true
|
||||
|
||||
PLIST_SOURCE="$APP_PATH/Contents/Resources/$PLIST_NAME"
|
||||
if [ -f "$PLIST_SOURCE" ]; then
|
||||
mv -f "$PLIST_SOURCE" "$LAUNCH_DAEMONS_PLIST_NAME" 2>> $LOG_FILE
|
||||
run_cmd mv -f "$PLIST_SOURCE" "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
else
|
||||
echo "`date` ERROR: service plist not found at $PLIST_SOURCE" >> $LOG_FILE
|
||||
log "ERROR: service plist not found at $PLIST_SOURCE"
|
||||
fi
|
||||
|
||||
chown root:wheel "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
launchctl load "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
echo "`date` Launching ${APP_NAME} application" >> $LOG_FILE
|
||||
open -a "$APP_PATH" 2>> $LOG_FILE || true
|
||||
run_cmd chown root:wheel "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
run_cmd chmod 644 "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
run_cmd launchctl bootstrap system "$LAUNCH_DAEMONS_PLIST_NAME" || run_cmd launchctl load "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
run_cmd launchctl enable "system/$APP_NAME-service" || true
|
||||
run_cmd launchctl kickstart -k "system/$APP_NAME-service" || true
|
||||
run_cmd launchctl print "system/$APP_NAME-service" || true
|
||||
log "Launching ${APP_NAME} application"
|
||||
run_cmd open -a "$APP_PATH" || true
|
||||
|
||||
echo "`date` Service status: $?" >> $LOG_FILE
|
||||
echo "`date` Script finished" >> $LOG_FILE
|
||||
log "Script finished"
|
||||
|
||||
@@ -29,7 +29,7 @@ fi
|
||||
|
||||
# Unload the service if loaded and remove its plist file regardless
|
||||
if launchctl list "${APP_NAME}-service" &> /dev/null; then
|
||||
sudo launchctl unload "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
sudo launchctl bootout system "$LAUNCH_DAEMONS_PLIST_NAME" || sudo launchctl unload "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
fi
|
||||
sudo rm -f "$LAUNCH_DAEMONS_PLIST_NAME"
|
||||
|
||||
|
||||
+29
-15
@@ -1,9 +1,9 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
VERSION=$1
|
||||
|
||||
if [[ $VERSION = '' ]]; then
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo '::error::VERSION does not set. Exiting with error...'
|
||||
exit 1
|
||||
fi
|
||||
@@ -14,25 +14,39 @@ cd dist
|
||||
|
||||
echo $VERSION >> VERSION
|
||||
curl -s https://api.github.com/repos/amnezia-vpn/amnezia-client/releases/tags/$VERSION | jq -r .body | tr -d '\r' > CHANGELOG
|
||||
curl -s https://api.github.com/repos/amnezia-vpn/amnezia-client/releases/tags/$VERSION | jq -r .published_at > RELEASE_DATE
|
||||
|
||||
if [[ $(cat CHANGELOG) = null ]]; then
|
||||
echo '::error::Release does not exists. Exiting with error...'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_arm64-v8a.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_armeabi-v7a.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_x86.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_x86_64.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_arm64-v8a.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_armeabi-v7a.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_x86.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_x86_64.apk
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_linux_x64.tar.zip
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos.dmg
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos_old.dmg
|
||||
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_windows_x64.exe
|
||||
# Download files with error handling
|
||||
download_file() {
|
||||
local url=$1
|
||||
local filename=$(basename "$url")
|
||||
echo "Downloading $filename..."
|
||||
if ! wget -q "$url"; then
|
||||
echo "::error::Failed to download $filename from $url"
|
||||
exit 8
|
||||
fi
|
||||
echo "Successfully downloaded $filename"
|
||||
}
|
||||
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android9+_arm64-v8a.apk
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android9+_armeabi-v7a.apk
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android9+_x86.apk
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android9+_x86_64.apk
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_linux_x64.tar
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos.pkg
|
||||
download_file https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_x64.exe
|
||||
|
||||
cd ../
|
||||
|
||||
rclone sync ./dist/ r2:/updates/
|
||||
echo "Syncing to R2..."
|
||||
if ! rclone sync ./dist/ r2:/updates/; then
|
||||
echo "::error::Failed to sync files to R2"
|
||||
exit 8
|
||||
fi
|
||||
|
||||
echo "Deployment completed successfully!"
|
||||
|
||||
Reference in New Issue
Block a user