Compare commits

..

10 Commits

Author SHA1 Message Date
spectrum 07b43df2bf Address remaining macOS recipe review comments 2026-05-29 18:34:22 +03:00
spectrum 0a85137d37 Disable Xcode signing for non-NE macOS 2026-05-29 16:31:11 +03:00
spectrum 9b8b716479 Isolate awg-go universal builds 2026-05-29 15:31:39 +03:00
spectrum c9befdfaad Address macOS build review comments 2026-05-29 13:56:19 +03:00
spectrum 6e7925b534 Sign macOS OpenVPN helper script 2026-05-26 15:59:39 +03:00
spectrum cbecca407c Fix macOS universal recipe builds 2026-05-26 15:50:10 +03:00
Yaroslav Gurov 01227fbd72 feat: rework amnezia-xray-bindings for multiarch 2026-05-26 15:27:02 +03:00
Yaroslav Gurov ca54ddcc83 chore: remove parallel thingy from CI/CD 2026-05-26 15:27:02 +03:00
spectrum c62cdf810a Build macOS prebuilts for arm64 and x86_64 2026-05-26 15:27:02 +03:00
Yaroslav Gurov c714d98bd1 chore: extend prebuilts support for MacOS NE by clang 21+ (#2633)
* chore: extend prebuilts support for MacOS NE by clang 21+

* chore: trigger prebuilts on workflow file changes
2026-05-25 22:05:56 +08:00
35 changed files with 205 additions and 1420 deletions
+7 -2
View File
@@ -22,6 +22,7 @@ jobs:
recipes:
- 'recipes/**'
- 'conanfile.py'
- '.github/workflows/deploy.yml'
Bake-Prebuilts-Linux:
runs-on: ubuntu-latest
@@ -539,13 +540,17 @@ jobs:
# ------------------------------------------------------
Bake-Prebuilts-MacOS-NE:
runs-on: macos-latest
needs: Detect-Changes
if: needs.Detect-Changes.outputs.recipes_changed == 'true'
strategy:
matrix:
xcode-version: [16.2, 16.4]
xcode-version: [16.2, 16.4, 26.4]
include:
- xcode-version: 26.4
os: macos-26
runs-on: ${{ matrix.os || 'macos-latest' }}
steps:
- uses: actions/checkout@v4
+4
View File
@@ -240,6 +240,10 @@ install(SCRIPT ${QT_DEPLOY_SCRIPT}
if (APPLE AND NOT IOS AND NOT MACOS_NE)
list(APPEND OVPN_SCRIPTS "${CMAKE_SOURCE_DIR}/deploy/data/macos/update-resolv-conf.sh")
set_target_properties(${PROJECT} PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
)
endif()
if (LINUX AND NOT ANDROID)
list(APPEND OVPN_SCRIPTS "${CMAKE_SOURCE_DIR}/deploy/data/linux/update-resolv-conf.sh")
@@ -192,36 +192,6 @@ void SettingsController::clearSettings()
toggleAutoStart(false);
}
bool SettingsController::isFileEncryptionEnabled()
{
return m_appSettingsRepository->isFileEncryption();
}
void SettingsController::toggleFileEncryption(bool enable)
{
m_appSettingsRepository->setFileEncryption(enable);
}
void SettingsController::setPassword(QString pwd)
{
m_appSettingsRepository->setPassword(pwd);
}
QString SettingsController::getPassword()
{
return m_appSettingsRepository->getPassword();
}
void SettingsController::setHint(QString hint)
{
m_appSettingsRepository->setHint(hint);
}
QString SettingsController::getHint()
{
return m_appSettingsRepository->getHint();
}
bool SettingsController::isAutoConnectEnabled() const
{
return m_appSettingsRepository->isAutoConnect();
@@ -44,15 +44,6 @@ public:
void clearSettings();
bool isFileEncryptionEnabled();
void toggleFileEncryption(bool enable);
void setPassword(QString pwd);
QString getPassword();
void setHint(QString hint);
QString getHint();
bool isAutoConnectEnabled() const;
void toggleAutoConnect(bool enable);
@@ -300,33 +300,6 @@ void SecureAppSettingsRepository::setStrictKillSwitchEnabled(bool enabled)
setValue("Conf/strictKillSwitchEnabled", enabled);
}
bool SecureAppSettingsRepository::isFileEncryption() const
{
return value("Sec/fileEncryption", false).toBool();
}
void SecureAppSettingsRepository::setFileEncryption(bool enabled)
{
setValue("Sec/fileEncryption", enabled);
}
QString SecureAppSettingsRepository::getPassword() const
{
return value("Sec/password", "").toString();
}
void SecureAppSettingsRepository::setPassword(const QString &pwd)
{
setValue("Sec/password", pwd);
}
QString SecureAppSettingsRepository::getHint() const
{
return value("Sec/hint", "").toString();
}
void SecureAppSettingsRepository::setHint(const QString &hint)
{
setValue("Sec/hint", hint);
}
bool SecureAppSettingsRepository::isAutoConnect() const
{
return value("Conf/autoConnect", false).toBool();
@@ -64,13 +64,6 @@ public:
void setKillSwitchEnabled(bool enabled);
bool isStrictKillSwitchEnabled() const;
void setStrictKillSwitchEnabled(bool enabled);
bool isFileEncryption() const;
void setFileEncryption(bool enabled);
QString getPassword() const;
void setPassword(const QString &pwd);
QString getHint() const;
void setHint(const QString &hint);
bool isAutoConnect() const;
void setAutoConnect(bool enabled);
-3
View File
@@ -1,3 +0,0 @@
<svg width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.5 5V3C2.5 2.33696 2.76339 1.70107 3.23223 1.23223C3.70107 0.763392 4.33696 0.5 5 0.5C5.66304 0.5 6.29893 0.763392 6.76777 1.23223C7.23661 1.70107 7.5 2.33696 7.5 3V5M1.5 5H8.5C9.05229 5 9.5 5.44772 9.5 6V9.5C9.5 10.0523 9.05229 10.5 8.5 10.5H1.5C0.947715 10.5 0.5 10.0523 0.5 9.5V6C0.5 5.44772 0.947715 5 1.5 5Z" stroke="#EB5757" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 494 B

-3
View File
@@ -1,3 +0,0 @@
<svg width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.5 5.00252V3.00252C2.49938 2.38254 2.72914 1.78445 3.14469 1.32435C3.56023 0.864252 4.13191 0.574969 4.74875 0.512663C5.36559 0.450356 5.98357 0.61947 6.48274 0.987175C6.9819 1.35488 7.32663 1.89494 7.45 2.50252M1.5 5.00252H8.5C9.05229 5.00252 9.5 5.45023 9.5 6.00252V9.50252C9.5 10.0548 9.05229 10.5025 8.5 10.5025H1.5C0.947715 10.5025 0.5 10.0548 0.5 9.50252V6.00252C0.5 5.45023 0.947715 5.00252 1.5 5.00252Z" stroke="#5CAEE7" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 592 B

-2
View File
@@ -36,8 +36,6 @@
<file>controls/home.svg</file>
<file>controls/infinity.svg</file>
<file>controls/info.svg</file>
<file>controls/lock-locked.svg</file>
<file>controls/lock-unlocked.svg</file>
<file>controls/mail.svg</file>
<file>controls/map-pin.svg</file>
<file>controls/more-vertical.svg</file>
+1 -1
View File
@@ -45,7 +45,7 @@ private:
QStringList encryptedKeys; // encode only key listed here
// only this fields need for backup
QStringList m_fieldsToBackup = {
"Conf/", "Servers/", "Sec/",
"Conf/", "Servers/",
};
mutable QByteArray m_key;
@@ -117,8 +117,6 @@ bool SubscriptionUiController::exportNativeConfig(const QString &serverId, const
}
const bool saved = SystemController::saveFile(fileName, nativeConfig);
if (m_settingsController->isFileEncryptionEnabled())
SystemController::encryptFile(fileName, m_settingsController->getPassword(), m_settingsController->getHint());
getAccountInfo(serverId, true);
return saved;
}
@@ -37,9 +37,6 @@ namespace PageLoader
PageSettingsSplitTunneling,
PageSettingsAppSplitTunneling,
PageSettingsKillSwitch,
PageSettingsAppEncryption,
PageSettingsAppPassword,
PageSettingsAppPasswordConfirm,
PageSettingsApiServerInfo,
PageSettingsApiAvailableCountries,
PageSettingsApiSupport,
@@ -139,8 +139,6 @@ void SettingsUiController::backupAppConfig(const QString &fileName)
if (!SystemController::saveFile(fileName, data)) {
qInfo() << "SettingsUiController::backupAppConfig: save or share was cancelled or failed";
}
if (isFileEncryptionEnabled())
SystemController::encryptFile(fileName, getPassword(), getHint());
}
void SettingsUiController::restoreAppConfig(const QString &fileName)
@@ -188,57 +186,6 @@ void SettingsUiController::clearSettings()
#endif
}
bool SettingsUiController::isFileEncryptionEnabled()
{
return m_settingsController->isFileEncryptionEnabled();
}
void SettingsUiController::toggleFileEncryption(bool enable)
{
m_settingsController->toggleFileEncryption(enable);
emit fileEncryptionStateChanged();
}
void SettingsUiController::setPassword(QString pwd)
{
m_settingsController->setPassword(pwd);
}
QString SettingsUiController::getPassword()
{
return m_settingsController->getPassword();
}
void SettingsUiController::setHint(QString hint)
{
m_settingsController->setHint(hint);
}
QString SettingsUiController::getHint()
{
return m_settingsController->getHint();
}
void SettingsUiController::setTempPassword(QString pwd)
{
tempPassword = pwd;
}
QString SettingsUiController::getTempPassword()
{
return tempPassword;
}
void SettingsUiController::setTempHint(QString hint)
{
tempHint = hint;
}
QString SettingsUiController::getTempHint()
{
return tempHint;
}
bool SettingsUiController::isAutoConnectEnabled()
{
return m_settingsController->isAutoConnectEnabled();
@@ -61,14 +61,6 @@ public slots:
void clearSettings();
bool isFileEncryptionEnabled();
void toggleFileEncryption(bool enable);
void setPassword(QString pwd);
QString getPassword();
void setHint(QString hint);
QString getHint();
bool isAutoConnectEnabled();
void toggleAutoConnect(bool enable);
@@ -81,11 +73,6 @@ public slots:
bool isNewsNotificationsEnabled();
void toggleNewsNotificationsEnabled(bool enable);
void setTempPassword(QString pwd);
QString getTempPassword();
void setTempHint(QString hint);
QString getTempHint();
bool isScreenshotsEnabled();
void toggleScreenshotsEnabled(bool enable);
@@ -150,13 +137,7 @@ signals:
void isHomeAdLabelVisibleChanged(bool visible);
void startMinimizedChanged();
void fileEncryptionStateChanged();
void changingPassword();
private:
QString tempPassword;
QString tempHint;
SettingsController* m_settingsController;
ServersController* m_serversController;
LanguageUiController* m_languageUiController;
-322
View File
@@ -11,21 +11,6 @@
#include <QUrl>
#include <QtConcurrent>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
namespace
{
constexpr int SALT_LEN = 16;
constexpr int IV_LEN = 12;
constexpr int KEY_LEN = 32;
constexpr int TAG_LEN = 16;
constexpr int PBKDF2_ITER = 100000;
const QByteArray magicString { "EncData" };
}
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#endif
@@ -119,313 +104,6 @@ bool SystemController::readFile(const QString &fileName, QString &data)
return true;
}
static QString opensslErrString()
{
unsigned long e = ERR_get_error();
if (!e)
return QStringLiteral("Unknown OpenSSL error");
char buf[256];
ERR_error_string_n(e, buf, sizeof(buf));
return QString::fromUtf8(buf);
}
static bool deriveKey(const QByteArray &password, const QByteArray &salt, QByteArray &outKey)
{
outKey.resize(KEY_LEN);
const unsigned char *pw = reinterpret_cast<const unsigned char *>(password.constData());
const unsigned char *s = reinterpret_cast<const unsigned char *>(salt.constData());
int ok = PKCS5_PBKDF2_HMAC(reinterpret_cast<const char *>(pw), password.size(), s, salt.size(), PBKDF2_ITER,
EVP_sha256(), KEY_LEN, reinterpret_cast<unsigned char *>(outKey.data()));
if (!ok) {
qDebug() << opensslErrString();
}
return ok == 1;
}
static bool aesCrypt(const QByteArray &in, const QByteArray &key, const QByteArray &iv, QByteArray &out,
QByteArray &tag, bool encrypt)
{
std::unique_ptr<EVP_CIPHER_CTX, void (*)(EVP_CIPHER_CTX *)> ctx { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
if (!ctx) {
qDebug() << "EVP_CIPHER_CTX_new failed";
return false;
}
const EVP_CIPHER *cipher = EVP_aes_256_gcm();
if (1 != EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, encrypt ? 1 : 0)) {
qDebug() << opensslErrString();
return false;
}
if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
qDebug() << opensslErrString();
return false;
}
if (1 != EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, reinterpret_cast<const unsigned char *>(key.constData()),
reinterpret_cast<const unsigned char *>(iv.constData()), -1)) {
qDebug() << opensslErrString();
return false;
}
out.clear();
out.resize(in.size());
int outlen = 0;
if (1 != EVP_CipherUpdate(ctx.get(), reinterpret_cast<unsigned char *>(out.data()), &outlen,
reinterpret_cast<const unsigned char *>(in.constData()), in.size())) {
qDebug() << opensslErrString();
return false;
}
int tmplen = 0;
if (encrypt) {
if (1 != EVP_CipherFinal_ex(ctx.get(), reinterpret_cast<unsigned char *>(out.data()) + outlen, &tmplen)) {
qDebug() << opensslErrString();
return false;
}
out.resize(outlen + tmplen);
tag.resize(TAG_LEN);
if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, TAG_LEN, tag.data())) {
qDebug() << opensslErrString();
return false;
}
} else {
if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char *>(tag.constData()))) {
qDebug() << opensslErrString();
return false;
}
if (1 != EVP_CipherFinal_ex(ctx.get(), reinterpret_cast<unsigned char *>(out.data()) + outlen, &tmplen)) {
qDebug() << "Authentication failed: " << opensslErrString();
return false;
}
out.resize(outlen + tmplen);
}
return true;
}
bool SystemController::encryptFile(const QString &filePath, const QString &password, const QString &hint)
{
QFile f(filePath);
if (!f.open(QIODevice::ReadOnly)) {
qDebug() << "Cannot open file for read: " << f.errorString();
return false;
}
QByteArray content = f.readAll();
f.close();
if (content.startsWith(magicString)) {
qDebug() << "File already encrypted";
return false;
}
QByteArray salt(SALT_LEN, 0);
QByteArray iv(IV_LEN, 0);
QByteArray key;
QByteArray cipher;
QByteArray tag;
if (1 != RAND_bytes(reinterpret_cast<unsigned char *>(salt.data()), SALT_LEN)
|| 1 != RAND_bytes(reinterpret_cast<unsigned char *>(iv.data()), IV_LEN)) {
qDebug() << opensslErrString();
return false;
}
if (!deriveKey(password.toUtf8(), salt, key))
return false;
if (!aesCrypt(content, key, iv, cipher, tag, true))
return false;
QByteArray out;
QByteArray hintBytes = hint.toUtf8();
quint32 hintLen = static_cast<quint32>(hintBytes.size());
out += magicString;
out.append(reinterpret_cast<const char *>(&hintLen), sizeof(hintLen));
out += hintBytes;
out += salt;
out += iv;
out += tag;
out += cipher;
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug() << "Cannot open file for write: " << f.errorString();
return false;
}
if (f.write(out) != out.size()) {
qDebug() << "Write failed";
f.close();
return false;
}
f.close();
return true;
}
QByteArray SystemController::getDecryptedData(const QString &filePath, const QString &password)
{
QFile f(filePath);
if (!f.open(QIODevice::ReadOnly)) {
qDebug() << "Cannot open file: " << f.errorString();
return {};
}
QByteArray content = f.readAll();
f.close();
if (!content.startsWith(magicString)) {
qDebug() << "Invalid file format (magic missing)";
return {};
}
int pos = magicString.size();
if (content.size() < pos + static_cast<int>(sizeof(quint32))) {
qDebug() << "Corrupted file (no hint length)";
return {};
}
quint32 hintLen = 0;
memcpy(&hintLen, content.constData() + pos, sizeof(quint32));
pos += sizeof(quint32);
if (content.size() < pos + static_cast<int>(hintLen) + SALT_LEN + IV_LEN + TAG_LEN) {
qDebug() << "Corrupted file (invalid sizes)";
return {};
}
pos += hintLen;
QByteArray salt = content.mid(pos, SALT_LEN);
pos += SALT_LEN;
QByteArray iv = content.mid(pos, IV_LEN);
pos += IV_LEN;
QByteArray tag = content.mid(pos, TAG_LEN);
pos += TAG_LEN;
QByteArray cipher = content.mid(pos);
QByteArray key;
if (!deriveKey(password.toUtf8(), salt, key)) {
qDebug() << "Key derivation failed";
return {};
}
QByteArray plain;
if (!aesCrypt(cipher, key, iv, plain, tag, false)) {
qDebug() << "Decryption failed (wrong password or corrupted data)";
return {};
}
return plain;
}
bool SystemController::isFileEncrypted(const QString &filePath)
{
QFile f(filePath);
if (!f.open(QIODevice::ReadOnly)) {
qDebug() << "Cannot open file for read: %1", f.errorString();
return false;
}
QByteArray data = f.readAll();
f.close();
if (!data.startsWith(magicString)) {
qDebug() << "File is not recognized as encrypted (magic missing)";
return false;
}
return true;
}
bool SystemController::isPasswordValid(const QString &filePath, const QString &password)
{
QFile f(filePath);
if (!f.open(QIODevice::ReadOnly)) {
qDebug() << f.errorString();
return false;
}
QByteArray content = f.readAll();
f.close();
if (!content.startsWith(magicString))
return false;
int pos = magicString.size();
quint32 hintLen = 0;
memcpy(&hintLen, content.constData() + pos, sizeof(quint32));
pos += sizeof(quint32);
pos += hintLen;
QByteArray salt = content.mid(pos, SALT_LEN);
pos += SALT_LEN;
QByteArray iv = content.mid(pos, IV_LEN);
pos += IV_LEN;
QByteArray tag = content.mid(pos, TAG_LEN);
pos += TAG_LEN;
QByteArray cipher = content.mid(pos);
QByteArray key;
if (!deriveKey(password.toUtf8(), salt, key))
return false;
QByteArray plain;
bool ok = aesCrypt(cipher, key, iv, plain, tag, false);
if (!ok)
qDebug() << "Wrong password";
return ok;
}
QString SystemController::readHint(const QString &filePath)
{
if (filePath.isEmpty())
return "";
QByteArray data;
readFile(filePath, data);
if (!data.startsWith(magicString)) {
qDebug() << "Not an encrypted file";
return {};
}
int pos = magicString.size();
if (data.size() < pos + static_cast<int>(sizeof(quint32))) {
qDebug() << "Corrupted file (no hint length)";
return {};
}
quint32 hintLen = 0;
memcpy(&hintLen, data.constData() + pos, sizeof(quint32));
pos += sizeof(quint32);
if (data.size() < pos + static_cast<int>(hintLen)) {
qDebug() << "Corrupted file (hint truncated)";
return {};
}
return QString::fromUtf8(data.constData() + pos, hintLen);
}
QString SystemController::getFileName(const QString &acceptLabel, const QString &nameFilter,
const QString &selectedFile, const bool isSaveMode, const QString &defaultSuffix)
{
-13
View File
@@ -15,23 +15,10 @@ public:
static bool readFile(const QString &fileName, QByteArray &data);
static bool readFile(const QString &fileName, QString &data);
static bool encryptFile(const QString &filePath, const QString &password, const QString &hint);
Q_INVOKABLE bool QEncryptFile(const QString &filePath, const QString &password, const QString &hint)
{
return encryptFile(filePath, password, hint);
}
public slots:
QString getFileName(const QString &acceptLabel, const QString &nameFilter, const QString &selectedFile = "",
const bool isSaveMode = false, const QString &defaultSuffix = "");
QByteArray getDecryptedData(const QString &filePath, const QString &password);
bool isFileEncrypted(const QString &filePath);
bool isPasswordValid(const QString &filePath, const QString &password);
QString readHint(const QString &filePath);
void setQmlRoot(QObject *qmlRoot);
bool isAuthenticated();
@@ -1,86 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
Rectangle {
id: root
property bool linkEnabled: false
property string textColor: AmneziaStyle.color.paleGray
property string textString
property int textFormat: Text.PlainText
property string iconPath
property real iconWidth: 16
property real iconHeight: 16
color: AmneziaStyle.color.onyxBlack
radius: 32
implicitHeight: iconHeight + 8
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
RowLayout {
id: content
anchors.centerIn: parent
spacing: 0
Image {
width: root.iconWidth
height: root.iconHeight
source: root.iconPath
}
CaptionTextType {
id: supportingText
Layout.fillWidth: true
Layout.leftMargin: 8
text: root.textString
textFormat: Text.RichText
color: root.textColor
}
BasicButtonType {
visible: root.linkEnabled
hoverEnabled: false
implicitHeight: root.iconHeight
implicitWidth: linkText.width/2 + 8
defaultColor: AmneziaStyle.color.transparent
CaptionTextType {
id: linkText
leftPadding: 4
width: linkText.text.length * linkText.font.pixelSize
text: qsTr("Learn more")
textFormat: Text.RichText
color: AmneziaStyle.color.goldenApricot
}
clickedFunc: function() {
Qt.openUrlExternally("https://storage.googleapis.com/amnezia/docs?m-path=/documentation/instructions/encryption")
}
}
}
}
-130
View File
@@ -1,130 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
id: root
objectName: "passwordDrawer"
property bool fromOutside: true
property string fileName
property var securedFunc
signal restoreSecuredBackup
signal importSecuredFile
expandedStateContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: root
function onRestoreSecuredBackup() {
root.securedFunc = function() {
SettingsController.restoreAppConfigFromData(SystemController.getDecryptedData(fileName, passwordField.textField.text))
}
passwordDrawer.openTriggered()
}
function onImportSecuredFile() {
root.securedFunc = function() {
if (ImportController.extractConfigFromData(SystemController.getDecryptedData(fileName, passwordField.textField.text))) {
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
passwordDrawer.openTriggered()
}
}
Header2TextType {
Layout.fillWidth: true
Layout.bottomMargin: 8
text: qsTr("Password required")
}
TextFieldWithHeaderType {
id: passwordField
Connections {
target: root
function onCloseTriggered() {
passwordField.textField.text = ""
}
}
property bool hideContent: true
Layout.fillWidth: true
headerText: qsTr("Password")
textField.echoMode: hideContent ? TextInput.Password : TextInput.Normal
textField.text: textField.text
rightButtonClickedOnEnter: true
clickedFunc: function () {
hideContent = !hideContent
buttonImageSource = textField.text !== "" ? (hideContent ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") : ""
}
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
textField.onTextChanged: {
buttonImageSource = textField.text !== "" ? (hideContent ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") : ""
}
}
LabelTextType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.bottomMargin: 16
text: qsTr("Hint: ") + (fromOutside ? SystemController.readHint(fileName) : SettingsController.getHint())
}
BasicButtonType {
id: doneButton
Layout.fillWidth: true
text: qsTr("Done")
clickedFunc: function() {
if (fromOutside) {
if (!SystemController.isPasswordValid(fileName, passwordField.textField.text)) {
passwordField.errorText = qsTr("Invalid password")
return
}
} else {
if (passwordField.textField.text !== SettingsController.getPassword()) {
passwordField.errorText = qsTr("Invalid password")
return
}
}
if (root.securedFunc && typeof root.securedFunc === "function") {
root.securedFunc()
}
root.closeTriggered()
}
}
}
}
@@ -199,10 +199,11 @@ Item {
leftImageSource: root.buttonImageSource
anchors.top: content.top
anchors.bottom: content.bottom
anchors.right: content.right
height: root.errorText !== "" ? content.implicitHeight - errorField.height - 5: content.implicitHeight
width: root.errorText !== "" ? content.implicitHeight - errorField.height - 5: content.implicitHeight
height: content.implicitHeight
width: content.implicitHeight
squareLeftSide: true
clickedFunc: function() {
@@ -60,16 +60,6 @@ PageType {
headerText: qsTr("Configuration Files")
descriptionText: qsTr("For router setup or the AmneziaWG app")
}
EncryptionIndicator {
id: indicator
visible: SettingsController.isFileEncryptionEnabled()
linkEnabled: true
textString: qsTr("Encryption enabled.")
iconPath: "qrc:/images/controls/lock-locked.svg"
}
}
delegate: ColumnLayout {
@@ -1,187 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Config"
import "../Controls2/TextTypes"
import "../Components"
PageType {
id: root
property bool isChangingPassword: false
Connections {
target: SettingsController
function onFileEncryptionStateChanged() {
PageController.showBusyIndicator(true)
PageController.closePage()
SettingsController.isFileEncryptionEnabled() ? PageController.goToPage(PageEnum.PageSettingsAppEncryption) : PageController.goToPage(PageEnum.PageSettingsAppPassword)
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(SettingsController.isFileEncryptionEnabled() ? qsTr("Encryption enabled") : qsTr("Encryption disabled"))
}
}
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
backButtonFunction: function() {
PageController.closePage()
if (root.isChangingPassword) {
root.isChangingPassword = false
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Password & Encryption")
descriptionText: qsTr("Password protection for backups and configuration files.\nRequired to restore or import encrypted files.")
}
BasicButtonType {
Layout.leftMargin: 8
Layout.bottomMargin: 32
implicitHeight: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
text: qsTr("Learn more")
clickedFunc: function() {
Qt.openUrlExternally("https://storage.googleapis.com/amnezia/docs?m-path=/documentation/instructions/encryption")
}
}
EncryptionIndicator {
id: indicator
textString: qsTr("Password set. Encryption enabled")
iconPath: "qrc:/images/controls/lock-locked.svg"
}
BasicButtonType {
id: disableEncryptionButton
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Disable encryption")
clickedFunc: function() {
passwordDrawer.securedFunc = function() {
PageController.showBusyIndicator(true)
SettingsController.toggleFileEncryption(false)
SettingsController.setPassword("")
SettingsController.setHint("")
PageController.showBusyIndicator(false)
}
passwordDrawer.openTriggered()
}
}
BasicButtonType {
id: changePasswordButton
hoveredColor: AmneziaStyle.color.slateGray
defaultColor: AmneziaStyle.color.midnightBlack
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Change password")
clickedFunc: function() {
passwordDrawer.securedFunc = function() {
root.isChangingPassword = true
PageController.showBusyIndicator(true)
PageController.closePage()
PageController.goToPage(PageEnum.PageSettingsAppPassword)
PageController.showBusyIndicator(false)
SettingsController.changingPassword()
}
passwordDrawer.openTriggered()
}
}
PasswordDrawer {
id: passwordDrawer
fromOutside: false
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.45
}
}
spacing: 16
footer: ColumnLayout {
width: listView.width
CaptionTextType {
Layout.fillWidth: true
Layout.topMargin: 32
horizontalAlignment: Text.AlignHCenter
textFormat: Text.RichText
text: qsTr("If the password is forgotten, it can be recovered. To reset the password, "
+ "<a href=\"appSettings\" style=\"text-decoration:none; color:%1;\">settings must be reset</a>."
+ "\nEncrypted files can only be opened with password used to encrypt them").arg(AmneziaStyle.color.goldenApricot)
color: AmneziaStyle.color.mutedGray
onLinkActivated: function(link) {
if (link === "appSettings") {
PageController.closePage()
}
}
}
}
}
}
@@ -1,215 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Config"
import "../Controls2/TextTypes"
import "../Components"
PageType {
id: root
property bool isChangingPassword: false
Connections {
target: SettingsController
function onChangingPassword() {
root.isChangingPassword = true
}
}
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
backButtonFunction: function() {
PageController.closePage()
if (root.isChangingPassword) {
root.isChangingPassword = false
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: root.isChangingPassword ? qsTr("Change password") : qsTr("Password & Encryption")
descriptionText: root.isChangingPassword ? qsTr("Existing encrypted files will still require the old password.\nThe new password will be used for new encrypted files.")
: qsTr("Password protection for backups and configuration files.\nRequired to restore or import encrypted files.")
}
BasicButtonType {
Layout.leftMargin: 8
Layout.bottomMargin: 32
implicitHeight: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
text: qsTr("Learn more")
clickedFunc: function() {
Qt.openUrlExternally("https://storage.googleapis.com/amnezia/docs?m-path=/documentation/instructions/encryption")
}
}
EncryptionIndicator {
id: indicator
visible: !root.isChangingPassword
textString: qsTr("Password not set. Encryption disabled")
iconPath: "qrc:/images/controls/lock-unlocked.svg"
}
}
model: inputFields
spacing: 16
delegate: ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: delegate
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: title
textField.echoMode: hideContent ? TextInput.Password : TextInput.Normal
textField.placeholderText: placeholderContent
textField.text: textField.text
rightButtonClickedOnEnter: true
clickedFunc: function () {
clickedHandler()
buttonImageSource = textField.text !== "" ? imageSource : ""
}
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
textField.onTextChanged: {
buttonImageSource = textField.text !== "" ? imageSource : ""
}
}
}
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: continueButton
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Continue")
clickedFunc: function() {
if (!root.isPasswordProperlyFilled()) {
return
}
var _password = listView.itemAtIndex(vars.passwordIndex).children[0].textField.text
var _hint = listView.itemAtIndex(vars.hintIndex).children[0].textField.text
SettingsController.setTempPassword(_password)
SettingsController.setTempHint(_hint)
PageController.goToPage(PageEnum.PageSettingsAppPasswordConfirm)
if (root.isChangingPassword) {
SettingsController.changingPassword()
}
}
}
}
}
function isPasswordProperlyFilled() {
var tooShort = false
var secretDataItem = listView.itemAtIndex(vars.passwordIndex).children[0]
if (secretDataItem.textField.text === "") {
secretDataItem.errorText = qsTr("Password cannot be empty")
tooShort = true
} else if (secretDataItem.textField.text.length < 4) {
secretDataItem.errorText = qsTr("Password too short")
tooShort = true
}
return !tooShort
}
property list<QtObject> inputFields: [
passwordObject,
hintObject
]
QtObject {
id: passwordObject
property string title: root.isChangingPassword ? qsTr("New password") : qsTr("Set encryption password")
readonly property string placeholderContent: ""
property string imageSource: "qrc:/images/controls/eye.svg"
property bool hideContent: true
readonly property var clickedHandler: function() {
hideContent = !hideContent
imageSource = hideContent ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
}
}
QtObject {
id: hintObject
property string title: root.isChangingPassword ? qsTr("New password hint (optional)") : qsTr("Password hint")
readonly property string placeholderContent: ""
property string imageSource: ""
property bool hideContent: false
readonly property var clickedHandler: undefined
}
QtObject {
id: vars
readonly property int passwordIndex: 0
readonly property int hintIndex: 1
}
}
@@ -1,155 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Config"
import "../Controls2/TextTypes"
PageType {
id: root
property bool isChangingPassword: false
Connections {
target: SettingsController
function onChangingPassword() {
root.isChangingPassword = true
}
}
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: root.isChangingPassword ? qsTr("Confirm new password") : qsTr("Confirm password")
descriptionText: root.isChangingPassword ? qsTr("") : qsTr("If the password is forgotten, it cant be recovered. "
+ "To reset the password, the app settings must be reset.\n"
+ "Encrypted files can only be opened with the password used to encrypt them")
}
}
model: 1 // fake model
spacing: 16
delegate: ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: delegate
property bool hideContent: true
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: root.isChangingPassword ? qsTr("Re-enter new password") : qsTr("Re-enter password")
textField.echoMode: hideContent ? TextInput.Password : TextInput.Normal
textField.placeholderText: ""
textField.text: textField.text
rightButtonClickedOnEnter: true
clickedFunc: function () {
hideContent = !hideContent
buttonImageSource = textField.text !== "" ? (hideContent ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") : ""
}
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
textField.onTextChanged: {
buttonImageSource = textField.text !== "" ? (hideContent ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") : ""
}
}
}
footer: ColumnLayout {
width: listView.width
LabelTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
text: qsTr("Hint: ") + SettingsController.getTempHint()
}
BasicButtonType {
id: continueButton
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: root.isChangingPassword ? qsTr("Save new password") : qsTr("Turn on encryption")
clickedFunc: function() {
if (!root.isPasswordProperlyFilled()) {
return
}
SettingsController.setPassword(SettingsController.getTempPassword())
SettingsController.setHint(SettingsController.getTempHint())
SettingsController.setTempPassword("")
SettingsController.setTempHint("")
PageController.closePage()
PageController.goToPage(PageEnum.PageSettings)
PageController.goToPage(PageEnum.PageSettingsAppEncryption)
SettingsController.toggleFileEncryption(true)
}
}
}
}
function isPasswordProperlyFilled() {
var notMatch = false
var secretDataItem = listView.itemAtIndex(0).children[0]
if (secretDataItem.textField.text !== SettingsController.getTempPassword()) {
secretDataItem.errorText = qsTr("Passwords not match")
notMatch = true
}
return !notMatch
}
}
@@ -213,23 +213,6 @@ PageType {
DividerType {}
LabelWithButtonType {
id: labelWithButtonAppPassword
Layout.fillWidth: true
text: qsTr("Password & Encryption")
descriptionText: qsTr("Password protection for backups and configuration files")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
SettingsController.getPassword() === "" ? PageController.goToPage(PageEnum.PageSettingsAppPassword)
: PageController.goToPage(PageEnum.PageSettingsAppEncryption)
}
}
DividerType {}
LabelWithButtonType {
id: labelWithButtonLogging
+1 -21
View File
@@ -67,16 +67,6 @@ PageType {
headerText: qsTr("Back up your configuration")
descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.")
}
EncryptionIndicator {
id: indicator
visible: SettingsController.isFileEncryptionEnabled()
linkEnabled: true
textString: qsTr("Encryption enabled.")
iconPath: "qrc:/images/controls/lock-locked.svg"
}
}
model: 1 // fake model to force the ListView to be created without a model
@@ -150,20 +140,10 @@ PageType {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
passwordDrawer.fileName = filePath
SystemController.isFileEncrypted(filePath) ? passwordDrawer.restoreSecuredBackup() : restoreBackup(filePath)
restoreBackup(filePath)
}
}
}
PasswordDrawer {
id: passwordDrawer
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.45
}
}
}
+6 -6
View File
@@ -48,8 +48,8 @@ PageType {
Layout.rightMargin: 16
headerText: qsTr("Logging")
descriptionText: qsTr("Logs help diagnose app errors and connection issues" +
"Logging is disabled by default. Enable it when troubleshooting or if requested by support")
descriptionText: qsTr("Enabling this function will save application's logs automatically. " +
"By default, logging functionality is disabled. Enable log saving in case of application malfunction.")
}
SwitcherType {
@@ -60,7 +60,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Enable logging")
text: qsTr("Enable logs")
checked: SettingsController.isLoggingEnabled
@@ -77,7 +77,7 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: -8
text: qsTr("Delete all logs")
text: qsTr("Clear logs")
leftImageSource: "qrc:/images/controls/trash.svg"
isSmallLeftImage: true
@@ -154,7 +154,7 @@ PageType {
Layout.topMargin: -8
Layout.bottomMargin: -8
text: qsTr("Save logs to file")
text: qsTr("Export logs")
leftImageSource: "qrc:/images/controls/save.svg"
isSmallLeftImage: true
@@ -178,7 +178,7 @@ PageType {
QtObject {
id: clientLogs
readonly property string title: qsTr("App logs")
readonly property string title: qsTr("Client logs")
readonly property string description: qsTr("AmneziaVPN logs")
readonly property bool isVisible: true
readonly property var openLogsHandler: function() {
@@ -12,7 +12,6 @@ import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
@@ -265,15 +264,6 @@ PageType {
}
}
PasswordDrawer {
id: passwordDrawer
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.45
}
property list<QtObject> variants: [
amneziaVpn,
selfHostVpn,
@@ -328,12 +318,7 @@ PageType {
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
PageController.showBusyIndicator(true)
if (SystemController.isFileEncrypted(filePath)) {
passwordDrawer.fileName = filePath
passwordDrawer.restoreSecuredBackup()
} else {
SettingsController.restoreAppConfig(filePath)
}
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
}
@@ -351,13 +336,8 @@ PageType {
var nameFilter = "Config files (*.vpn *.ovpn *.conf *.json)"
var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter)
if (fileName !== "") {
if (SystemController.isFileEncrypted(fileName)) {
passwordDrawer.fileName = fileName
passwordDrawer.importSecuredFile()
} else {
if (ImportController.extractConfigFromFile(fileName)) {
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}
if (ImportController.extractConfigFromFile(fileName)) {
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
}
-10
View File
@@ -271,16 +271,6 @@ PageType {
color: AmneziaStyle.color.mutedGray
}
EncryptionIndicator {
id: indicator
visible: SettingsController.isFileEncryptionEnabled()
linkEnabled: true
textString: qsTr("Encryption enabled.")
iconPath: "qrc:/images/controls/lock-locked.svg"
}
TextFieldWithHeaderType {
id: clientNameTextField
Layout.fillWidth: true
@@ -108,8 +108,6 @@ PageType {
if (fileName !== "") {
PageController.showBusyIndicator(true)
ExportController.exportConfig(fileName)
if (SettingsController.isFileEncryptionEnabled())
SystemController.QEncryptFile(fileName, SettingsController.getPassword(), SettingsController.getHint())
PageController.showBusyIndicator(false)
}
}
@@ -69,16 +69,6 @@ PageType {
color: AmneziaStyle.color.mutedGray
}
EncryptionIndicator {
id: indicator
visible: SettingsController.isFileEncryptionEnabled()
linkEnabled: true
textString: qsTr("Encryption enabled.")
iconPath: "qrc:/images/controls/lock-locked.svg"
}
DropDownType {
id: serverSelector
objectName: "serverSelector"
-5
View File
@@ -7,13 +7,11 @@
<file>Components/HomeContainersListView.qml</file>
<file>Components/HomeSplitTunnelingDrawer.qml</file>
<file>Components/InstalledAppsDrawer.qml</file>
<file>Components/PasswordDrawer.qml</file>
<file>Components/ChangelogDrawer.qml</file>
<file>Components/QuestionDrawer.qml</file>
<file>Components/SelectLanguageDrawer.qml</file>
<file>Components/ServersListView.qml</file>
<file>Components/SettingsContainersListView.qml</file>
<file>Components/EncryptionIndicator.qml</file>
<file>Components/BenefitRow.qml</file>
<file>Components/BenefitsPanel.qml</file>
<file>Components/SubscriptionExpiredDrawer.qml</file>
@@ -101,9 +99,6 @@
<file>Pages2/PageSettingsApiServerInfo.qml</file>
<file>Pages2/PageSettingsApplication.qml</file>
<file>Pages2/PageSettingsAppSplitTunneling.qml</file>
<file>Pages2/PageSettingsAppEncryption.qml</file>
<file>Pages2/PageSettingsAppPassword.qml</file>
<file>Pages2/PageSettingsAppPasswordConfirm.qml</file>
<file>Pages2/PageSettingsBackup.qml</file>
<file>Pages2/PageSettingsConnection.qml</file>
<file>Pages2/PageSettingsDns.qml</file>
+1 -1
View File
@@ -12,7 +12,7 @@ if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
else()
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
endif()
+71 -20
View File
@@ -1,16 +1,27 @@
from conan import ConanFile
from conan.tools.files import get, copy, collect_libs, chdir, rename
from conan.tools.files import get, copy, collect_libs, chdir, rename, mkdir
from conan.tools.layout import basic_layout
from conan.errors import ConanInvalidConfiguration
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.apple import XCRun, is_apple_os
from conan.tools.apple.apple import _to_apple_arch
import os
import shlex
from pathlib import Path
class AmneziaXrayBindings(ConanFile):
name = "amnezia-xray-bindings"
version = "1.1.0"
settings = "os", "arch", "compiler"
_arch_map = {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}
@property
def _goos(self):
return {
@@ -19,15 +30,15 @@ class AmneziaXrayBindings(ConanFile):
"Macos": "darwin",
"Windows": "windows"
}.get(str(self.settings.os))
@property
def _goarch(self):
return {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}.get(str(self.settings.arch))
def _archs(self):
return str(self.settings.arch).split("|")
@property
def _is_multiarch(self):
return len(self._archs) > 1
@property
def _is_windows(self):
return str(self.settings.os).startswith("Windows")
@@ -54,34 +65,72 @@ class AmneziaXrayBindings(ConanFile):
self.tool_requires("mingw-builds/15.1.0")
def validate(self):
if not self._goos or not self._goarch:
if not self._goos or not all(arch in self._arch_map for arch in self._archs):
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}"
)
if self._is_multiarch and not is_apple_os(self):
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support multiarch builds"
)
def source(self):
get(self, "https://github.com/amnezia-vpn/amnezia-xray-bindings/archive/v1.1.0.zip",
sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True)
def generate(self):
tc = AutotoolsToolchain(self)
tc.apple_arch_flag = None
tc.make_args = [
"LIB_ARC=libamnezia_xray.a"
]
env = tc.environment()
env.define("ARCH", self._goarch)
env.define("GOARCH", self._goarch)
env.define("GOPATH", os.path.join(self.build_folder, "gopath"))
env.define("GOMODCACHE", os.path.join(self.build_folder, "gopath", "pkg", "mod"))
env.define("GOCACHE", os.path.join(self.build_folder, "gocache"))
env.define("GOOS", self._goos)
env.define("CGO_LDFLAGS", tc.ldflags)
env.define("CGO_CFLAGS", tc.cflags)
if self._is_windows:
env.define("OS", "windows")
self._ldflags = tc.ldflags
self._cflags = tc.cflags
tc.generate(env)
def build(self):
with chdir(self, self.source_folder):
autotools = Autotools(self)
autotools.make()
for arch in self._archs:
cflags = list(self._cflags)
ldflags = list(self._ldflags)
if is_apple_os(self):
cflags.append(f"-arch {_to_apple_arch(arch)}")
ldflags.append(f"-arch {_to_apple_arch(arch)}")
autotools = Autotools(self)
autotools.make(args=[
f"BUILD_DIR={os.path.join('build', arch)}",
f"ARCH={self._arch_map.get(arch)}",
f"CGO_CFLAGS={shlex.quote(' '.join(cflags))}",
f"CGO_LDFLAGS={shlex.quote(' '.join(ldflags))}"
])
if is_apple_os(self) and self._is_multiarch:
merged_dir = os.path.join(self.source_folder, "merged")
archives = sorted(
str(path) for path in Path(self.source_folder).glob("build/*/*.a")
)
if not archives:
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} did not produce archives for {self.settings.arch}"
)
output = os.path.join(merged_dir, Path(archives[0]).name)
mkdir(self, merged_dir)
lipo = XCRun(self).find('lipo')
self.run("{} -create -output {} {}".format(
shlex.quote(lipo),
shlex.quote(output),
" ".join(shlex.quote(archive) for archive in archives)
))
def _rename_header(self):
if not self._is_windows:
@@ -99,10 +148,12 @@ class AmneziaXrayBindings(ConanFile):
os.rename(src, dst)
def package(self):
copy(self, "*.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include"))
copy(self, "*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"))
copy(self, "*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"))
copy(self, "*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"))
header_src = os.path.join(self.source_folder, "build", self._archs[0])
lib_src = os.path.join(self.source_folder, "merged") if self._is_multiarch else header_src
copy(self, "*.h", src=header_src, dst=os.path.join(self.package_folder, "include"), keep_path=False)
copy(self, "*.a", src=lib_src, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, "*.lib", src=lib_src, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, "*.dll", src=lib_src, dst=os.path.join(self.package_folder, "bin"), keep_path=False)
self._rename_header()
def package_info(self):
+58 -9
View File
@@ -1,16 +1,20 @@
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.layout import basic_layout
from conan.tools.files import get, copy
from conan.tools.files import get, copy, chdir
from conan.tools.apple import XCRun
from conan.tools.gnu import Autotools, AutotoolsToolchain
import os
import shlex
class AwgGo(ConanFile):
name = "awg-go"
version = "0.2.16"
package_type = "application"
settings = "os", "arch"
_binary_name = "amneziawg-go"
@property
def _goos(self):
@@ -21,12 +25,29 @@ class AwgGo(ConanFile):
}.get(str(self.settings.os))
@property
def _goarch(self):
def _arch_map(self):
return {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}.get(str(self.settings.arch))
}
@property
def _archs(self):
return str(self.settings.arch).split("|")
@property
def _goarch(self):
goarchs = [self._arch_map.get(arch) for arch in self._archs]
return goarchs[0] if len(goarchs) == 1 else None
@property
def _goarchs(self):
return [self._arch_map.get(arch) for arch in self._archs]
@property
def _is_universal_macos(self):
return str(self.settings.os) == "Macos" and len(self._archs) > 1
def layout(self):
basic_layout(self, build_folder=".")
@@ -35,7 +56,7 @@ class AwgGo(ConanFile):
self.tool_requires("go/1.26.0")
def validate(self):
if not self._goos or not self._goarch:
if not self._goos or not all(self._goarchs) or (len(self._archs) > 1 and not self._is_universal_macos):
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}"
)
@@ -48,20 +69,48 @@ class AwgGo(ConanFile):
def generate(self):
tc = AutotoolsToolchain(self)
env = tc.environment()
env.define("GOPATH", os.path.join(self.build_folder, "gopath"))
env.define("GOMODCACHE", os.path.join(self.build_folder, "gopath", "pkg", "mod"))
env.define("GOCACHE", os.path.join(self.build_folder, "gocache"))
env.define("GOTELEMETRY", "off")
env.define("GOOS", self._goos)
env.define("GOARCH", self._goarch)
env.define("CGO_LDFLAGS", tc.ldflags)
env.define("CGO_CFLAGS", tc.cflags)
tc.generate(env)
def build(self):
at = Autotools(self)
at.make()
outputs = []
with chdir(self, self.source_folder):
for goarch in self._goarchs:
arch_destdir = os.path.join(self.build_folder, f"build-{goarch}")
at = Autotools(self)
at.make("clean")
at.make("install", args=[
f"DESTDIR={shlex.quote(arch_destdir)}",
"BINDIR=",
f"GOARCH={goarch}",
])
output_path = os.path.join(arch_destdir, self._binary_name)
arch_output_path = os.path.join(self.build_folder, f"{self._binary_name}-{goarch}")
os.rename(output_path, arch_output_path)
outputs.append(arch_output_path)
output = os.path.join(self.build_folder, self._binary_name)
if self._is_universal_macos:
lipo = XCRun(self).find("lipo")
self.run("{} -create {} -output {}".format(
shlex.quote(lipo),
" ".join(shlex.quote(output) for output in outputs),
shlex.quote(output)
))
return
os.rename(outputs[0], output)
def package(self):
copy(self, "amneziawg-go", src=self.build_folder, dst=self.package_folder)
copy(self, self._binary_name, src=self.build_folder, dst=self.package_folder)
def package_info(self):
self.cpp_info.exe = True
self.cpp_info.location = os.path.join(self.package_folder, "amneziawg-go")
self.cpp_info.location = os.path.join(self.package_folder, self._binary_name)
self.cpp_info.set_property("cmake_target_name", "amnezia::awg-go")
+50 -15
View File
@@ -2,16 +2,24 @@ from conan import ConanFile
from conan.tools.layout import basic_layout
from conan.tools.files import get, copy, chdir
from conan.errors import ConanInvalidConfiguration
from conan.tools.apple import XCRun
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.env import Environment
import os
import shlex
class Tun2Socks(ConanFile):
name = "tun2socks"
version = "2.6.0"
package_type = "application"
settings = "os", "arch"
_binary_name = "tun2socks"
_arch_map = {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}
@property
def _goos(self):
@@ -22,17 +30,21 @@ class Tun2Socks(ConanFile):
}.get(str(self.settings.os))
@property
def _goarch(self):
return {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}.get(str(self.settings.arch))
def _archs(self):
return str(self.settings.arch).split("|")
@property
def _goarchs(self):
return [self._arch_map.get(arch) for arch in self._archs]
@property
def _is_universal_macos(self):
return str(self.settings.os) == "Macos" and len(self._archs) > 1
@property
def _is_windows(self):
return str(self.settings.get_safe("os")).startswith("Windows")
@property
def _ext(self):
return ".exe" if self._is_windows else ""
@@ -41,7 +53,7 @@ class Tun2Socks(ConanFile):
basic_layout(self)
def validate(self):
if not self._goos or not self._goarch:
if not self._goos or not all(self._goarchs) or (len(self._archs) > 1 and not self._is_universal_macos):
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}"
)
@@ -66,23 +78,46 @@ class Tun2Socks(ConanFile):
def generate(self):
tc = AutotoolsToolchain(self)
env = tc.environment()
env.define("GOPATH", os.path.join(self.build_folder, "gopath"))
env.define("GOMODCACHE", os.path.join(self.build_folder, "gopath", "pkg", "mod"))
env.define("GOCACHE", os.path.join(self.build_folder, "gocache"))
env.define("GOTELEMETRY", "off")
env.define("LDFLAGS", "")
env.define("CGO_LDFLAGS", tc.ldflags)
env.define("CGO_CFLAGS", tc.cflags)
env.define("GOOS", self._goos)
env.define("GOARCH", self._goarch)
tc.generate(env)
def build(self):
outputs = []
with chdir(self, self.source_folder):
at = Autotools(self)
at.make("tun2socks")
for goarch in self._goarchs:
target = f"{self._goos}-{goarch}"
at = Autotools(self)
at.make(target)
output_ext = ".exe" if self._goos == "windows" else ""
output_path = os.path.join(self.source_folder, "build", f"{self._binary_name}-{target}{output_ext}")
arch_output_path = os.path.join(self.build_folder, f"{self._binary_name}-{goarch}")
os.rename(output_path, arch_output_path)
outputs.append(arch_output_path)
output = os.path.join(self.build_folder, self._binary_name)
if self._is_universal_macos:
lipo = XCRun(self).find("lipo")
self.run("{} -create {} -output {}".format(
shlex.quote(lipo),
" ".join(shlex.quote(output) for output in outputs),
shlex.quote(output)
))
return
os.rename(outputs[0], output)
def package(self):
copy(self, "tun2socks", src=self.build_folder, dst=self.package_folder)
copy(self, self._binary_name, src=self.build_folder, dst=self.package_folder)
if self._is_windows:
with chdir(self, self.package_folder):
os.rename(src="tun2socks", dst="tun2socks.exe")
os.rename(src=self._binary_name, dst=f"{self._binary_name}.exe")
def package_info(self):
self.cpp_info.exe = True