mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
15 Commits
ant-remote
...
zwift_clic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cdd676b5d | ||
|
|
9d2a68cb28 | ||
|
|
b92bb58651 | ||
|
|
41970410d1 | ||
|
|
d2ef1607ad | ||
|
|
b6f76c9a5d | ||
|
|
73e9e44c86 | ||
|
|
bc8443e84d | ||
|
|
425480147e | ||
|
|
ce60ae7c35 | ||
|
|
2f157e7c50 | ||
|
|
c0535c63d4 | ||
|
|
9757f20d44 | ||
|
|
8dd314cb8c | ||
|
|
2d31add7a5 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -20,3 +20,6 @@
|
||||
path = zwiftplay
|
||||
url = https://github.com/cagnulein/zwiftplay.git
|
||||
branch = lib
|
||||
[submodule "src/ios/CryptoSwift"]
|
||||
path = src/ios/CryptoSwift
|
||||
url = https://github.com/krzyzanowskim/CryptoSwift.git
|
||||
|
||||
@@ -309,6 +309,15 @@
|
||||
876E50F42B701C050080FAAF /* moc_abstractZapDevice.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E50F12B701C040080FAAF /* moc_abstractZapDevice.cpp */; };
|
||||
876E50F52B701C050080FAAF /* moc_zwiftclickremote.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E50F22B701C040080FAAF /* moc_zwiftclickremote.cpp */; };
|
||||
876E51002B701C1E0080FAAF /* zwiftclickremote.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E50FB2B701C1E0080FAAF /* zwiftclickremote.cpp */; };
|
||||
876E51092B70FDA30080FAAF /* abstractZapDevice.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51022B70FDA30080FAAF /* abstractZapDevice.swift */; };
|
||||
876E510A2B70FDA30080FAAF /* zapCrypto.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51032B70FDA30080FAAF /* zapCrypto.swift */; };
|
||||
876E510B2B70FDA30080FAAF /* encryptionUtils.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51042B70FDA30080FAAF /* encryptionUtils.swift */; };
|
||||
876E510C2B70FDA30080FAAF /* zapConstants.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51052B70FDA30080FAAF /* zapConstants.swift */; };
|
||||
876E510D2B70FDA30080FAAF /* localKeyProvider.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51062B70FDA30080FAAF /* localKeyProvider.swift */; };
|
||||
876E510E2B70FDA30080FAAF /* zwiftPlayDevice.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51072B70FDA30080FAAF /* zwiftPlayDevice.swift */; };
|
||||
876E510F2B70FDA30080FAAF /* zapBleUuids.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876E51082B70FDA30080FAAF /* zapBleUuids.swift */; };
|
||||
876E51222B7146D90080FAAF /* CryptoSwift.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 876E51192B7146B00080FAAF /* CryptoSwift.framework */; };
|
||||
876E51232B7146D90080FAAF /* CryptoSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 876E51192B7146B00080FAAF /* CryptoSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
876ED21525C3E8DE0065F3DC /* ftmsbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876ED21025C3E8DD0065F3DC /* ftmsbike.cpp */; };
|
||||
876ED21625C3E8DE0065F3DC /* schwinnic4bike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876ED21425C3E8DE0065F3DC /* schwinnic4bike.cpp */; };
|
||||
876ED21925C3E9000065F3DC /* moc_ftmsbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876ED21725C3E9000065F3DC /* moc_ftmsbike.cpp */; };
|
||||
@@ -596,6 +605,41 @@
|
||||
remoteGlobalIDString = 876E4E102594747F00BD5714;
|
||||
remoteInfo = watchkit;
|
||||
};
|
||||
876E51182B7146B00080FAAF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 754BE45519693E190098E6F3;
|
||||
remoteInfo = CryptoSwift;
|
||||
};
|
||||
876E511A2B7146B00080FAAF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 75211F92207249D8004E41F8;
|
||||
remoteInfo = "CryptoSwift-TestHostApp";
|
||||
};
|
||||
876E511C2B7146B00080FAAF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 754BE46019693E190098E6F3;
|
||||
remoteInfo = CryptoSwiftTests;
|
||||
};
|
||||
876E511E2B7146B00080FAAF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 7595C14A2072E48C00EA1A5F;
|
||||
remoteInfo = "TestsPerformance-Mac";
|
||||
};
|
||||
876E51202B7146B00080FAAF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 7564F0602072EAEB00CA5A96;
|
||||
remoteInfo = "TestsPerformance-iOS";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -628,6 +672,7 @@
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
873D388C29B0D745006A2611 /* ConnectIQ.xcframework in Embed Frameworks */,
|
||||
876E51232B7146D90080FAAF /* CryptoSwift.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1118,6 +1163,14 @@
|
||||
876E50FD2B701C1E0080FAAF /* abstractZapDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = abstractZapDevice.h; path = ../src/zwift_play/abstractZapDevice.h; sourceTree = "<group>"; };
|
||||
876E50FE2B701C1E0080FAAF /* controllerNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = controllerNotification.h; path = ../src/zwift_play/controllerNotification.h; sourceTree = "<group>"; };
|
||||
876E50FF2B701C1E0080FAAF /* zwiftclickremote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zwiftclickremote.h; path = ../src/zwift_play/zwiftclickremote.h; sourceTree = "<group>"; };
|
||||
876E51022B70FDA30080FAAF /* abstractZapDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = abstractZapDevice.swift; path = ../src/ios/zwift_play/abstractZapDevice.swift; sourceTree = "<group>"; };
|
||||
876E51032B70FDA30080FAAF /* zapCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = zapCrypto.swift; path = ../src/ios/zwift_play/zapCrypto.swift; sourceTree = "<group>"; };
|
||||
876E51042B70FDA30080FAAF /* encryptionUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = encryptionUtils.swift; path = ../src/ios/zwift_play/encryptionUtils.swift; sourceTree = "<group>"; };
|
||||
876E51052B70FDA30080FAAF /* zapConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = zapConstants.swift; path = ../src/ios/zwift_play/zapConstants.swift; sourceTree = "<group>"; };
|
||||
876E51062B70FDA30080FAAF /* localKeyProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = localKeyProvider.swift; path = ../src/ios/zwift_play/localKeyProvider.swift; sourceTree = "<group>"; };
|
||||
876E51072B70FDA30080FAAF /* zwiftPlayDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = zwiftPlayDevice.swift; path = ../src/ios/zwift_play/zwiftPlayDevice.swift; sourceTree = "<group>"; };
|
||||
876E51082B70FDA30080FAAF /* zapBleUuids.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = zapBleUuids.swift; path = ../src/ios/zwift_play/zapBleUuids.swift; sourceTree = "<group>"; };
|
||||
876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CryptoSwift.xcodeproj; path = ../src/ios/CryptoSwift/CryptoSwift.xcodeproj; sourceTree = "<group>"; };
|
||||
876ED21025C3E8DD0065F3DC /* ftmsbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ftmsbike.cpp; path = ../src/ftmsbike.cpp; sourceTree = "<group>"; };
|
||||
876ED21125C3E8DD0065F3DC /* ftmsbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ftmsbike.h; path = ../src/ftmsbike.h; sourceTree = "<group>"; };
|
||||
876ED21225C3E8DD0065F3DC /* material.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = material.h; path = ../src/material.h; sourceTree = "<group>"; };
|
||||
@@ -1667,6 +1720,7 @@
|
||||
3D010A6A5D13BDBCE8308349 /* qtfreetype in Link Binary With Libraries */,
|
||||
3B6367B8479BE459243BC9A6 /* Qt5GraphicsSupport in Link Binary With Libraries */,
|
||||
A48EFCF98552C67DAB8515FD /* Qt5ClipboardSupport in Link Binary With Libraries */,
|
||||
876E51222B7146D90080FAAF /* CryptoSwift.framework in Link Binary With Libraries */,
|
||||
4B457EBD757B30AEB87115EA /* qgif in Link Binary With Libraries */,
|
||||
3CD4CA4EC80AF4F839D1019B /* qicns in Link Binary With Libraries */,
|
||||
B714316583081A00BDF9C0F2 /* qico in Link Binary With Libraries */,
|
||||
@@ -1954,6 +2008,7 @@
|
||||
2EB56BE3C2D93CDAB0C52E67 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
876E51012B70FD800080FAAF /* zwift_play */,
|
||||
876E50FD2B701C1E0080FAAF /* abstractZapDevice.h */,
|
||||
876E50FE2B701C1E0080FAAF /* controllerNotification.h */,
|
||||
876E50F62B701C1E0080FAAF /* encryptionUtils.h */,
|
||||
@@ -2414,6 +2469,32 @@
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
876E51012B70FD800080FAAF /* zwift_play */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
876E51022B70FDA30080FAAF /* abstractZapDevice.swift */,
|
||||
876E51042B70FDA30080FAAF /* encryptionUtils.swift */,
|
||||
876E51062B70FDA30080FAAF /* localKeyProvider.swift */,
|
||||
876E51082B70FDA30080FAAF /* zapBleUuids.swift */,
|
||||
876E51052B70FDA30080FAAF /* zapConstants.swift */,
|
||||
876E51032B70FDA30080FAAF /* zapCrypto.swift */,
|
||||
876E51072B70FDA30080FAAF /* zwiftPlayDevice.swift */,
|
||||
);
|
||||
name = zwift_play;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
876E51112B7146B00080FAAF /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
876E51192B7146B00080FAAF /* CryptoSwift.framework */,
|
||||
876E511B2B7146B00080FAAF /* CryptoSwift-TestHostApp.app */,
|
||||
876E511D2B7146B00080FAAF /* CryptoSwiftTests.xctest */,
|
||||
876E511F2B7146B00080FAAF /* TestsPerformance-Mac.xctest */,
|
||||
876E51212B7146B00080FAAF /* TestsPerformance-iOS.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
87917A6D28E768B000F8D9AC /* AppleWatchToIpad */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2437,6 +2518,7 @@
|
||||
AF39DD055C3EF8226FBE929D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */,
|
||||
87FA94682B6B8A5A00B6AB9A /* libSystem.B.tbd */,
|
||||
87FA94662B6B89FD00B6AB9A /* SwiftUI.framework */,
|
||||
8745B2742AFCB3B300991A39 /* libadb.a */,
|
||||
@@ -2959,6 +3041,12 @@
|
||||
);
|
||||
productRefGroup = FE0A091FDBFB3E9C31B7A1BD /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 876E51112B7146B00080FAAF /* Products */;
|
||||
ProjectRef = 876E51102B7146B00080FAAF /* CryptoSwift.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
799833E5566DEFFC37E4BF1E /* qdomyoszwift */,
|
||||
@@ -2969,6 +3057,44 @@
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
876E51192B7146B00080FAAF /* CryptoSwift.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = CryptoSwift.framework;
|
||||
remoteRef = 876E51182B7146B00080FAAF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
876E511B2B7146B00080FAAF /* CryptoSwift-TestHostApp.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = "CryptoSwift-TestHostApp.app";
|
||||
remoteRef = 876E511A2B7146B00080FAAF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
876E511D2B7146B00080FAAF /* CryptoSwiftTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = CryptoSwiftTests.xctest;
|
||||
remoteRef = 876E511C2B7146B00080FAAF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
876E511F2B7146B00080FAAF /* TestsPerformance-Mac.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "TestsPerformance-Mac.xctest";
|
||||
remoteRef = 876E511E2B7146B00080FAAF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
876E51212B7146B00080FAAF /* TestsPerformance-iOS.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = "TestsPerformance-iOS.xctest";
|
||||
remoteRef = 876E51202B7146B00080FAAF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
30414803F31797EB689AE508 /* Copy Bundle Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
@@ -3144,6 +3270,7 @@
|
||||
873824B927E64707004F1B46 /* moc_provider.cpp in Compile Sources */,
|
||||
8727A47727849EA600019B5D /* paferstreadmill.cpp in Compile Sources */,
|
||||
DF1FD9718B75FA591A7E3D80 /* fit_decode.cpp in Compile Sources */,
|
||||
876E510B2B70FDA30080FAAF /* encryptionUtils.swift in Compile Sources */,
|
||||
878C9E6B28B77E9800669129 /* moc_nordictrackifitadbbike.cpp in Compile Sources */,
|
||||
878A331D25AB50C300BD13E1 /* moc_yesoulbike.cpp in Compile Sources */,
|
||||
952DBD14DF6369E885020EF4 /* fit_developer_field.cpp in Compile Sources */,
|
||||
@@ -3157,6 +3284,7 @@
|
||||
87C5F0C326285E5F0067A1B5 /* mimeinlinefile.cpp in Compile Sources */,
|
||||
87646C2227B5065100F82131 /* moc_bhfitnesselliptical.cpp in Compile Sources */,
|
||||
876E51002B701C1E0080FAAF /* zwiftclickremote.cpp in Compile Sources */,
|
||||
876E510C2B70FDA30080FAAF /* zapConstants.swift in Compile Sources */,
|
||||
873824B127E64706004F1B46 /* moc_browser_p.cpp in Compile Sources */,
|
||||
873824B627E64707004F1B46 /* moc_hostname_p.cpp in Compile Sources */,
|
||||
87A0D7542A3A4547005147F2 /* moc_fakerower.cpp in Compile Sources */,
|
||||
@@ -3181,6 +3309,7 @@
|
||||
87E34C2D2886F99A00CEDE4B /* moc_octanetreadmill.cpp in Compile Sources */,
|
||||
87D91F9A2800B9970026D43C /* proformwifibike.cpp in Compile Sources */,
|
||||
873CD22327EF8E18000131BC /* inappstoreqmltype.cpp in Compile Sources */,
|
||||
876E510E2B70FDA30080FAAF /* zwiftPlayDevice.swift in Compile Sources */,
|
||||
87C481FA26DFA7C3006211AD /* eliterizer.cpp in Compile Sources */,
|
||||
873824EE27E647A9004F1B46 /* service.cpp in Compile Sources */,
|
||||
8772A0E625E43ADB0080718C /* trxappgateusbbike.cpp in Compile Sources */,
|
||||
@@ -3233,6 +3362,7 @@
|
||||
23191C28CB29474279752FD3 /* fit_protocol_validator.cpp in Compile Sources */,
|
||||
275D55B5D956B2E5F1B7E46E /* fit_unicode.cpp in Compile Sources */,
|
||||
87F527BE28EEB5AA00A9F8D5 /* qzsettings.cpp in Compile Sources */,
|
||||
876E510D2B70FDA30080FAAF /* localKeyProvider.swift in Compile Sources */,
|
||||
8703BAEB273C67A90058E206 /* pafersbike.cpp in Compile Sources */,
|
||||
87061399286D8D6500D2446E /* moc_wobjectdefs.cpp in Compile Sources */,
|
||||
873824BA27E64707004F1B46 /* moc_server_p.cpp in Compile Sources */,
|
||||
@@ -3257,6 +3387,7 @@
|
||||
87E2F85F291ED315002BDC65 /* moc_lifefitnesstreadmill.cpp in Compile Sources */,
|
||||
876BFCA127BE35D8001D7645 /* moc_bowflext216treadmill.cpp in Compile Sources */,
|
||||
25FCD41CCCAF49293B9369E8 /* qfit.cpp in Compile Sources */,
|
||||
876E510F2B70FDA30080FAAF /* zapBleUuids.swift in Compile Sources */,
|
||||
87ADD2BD27634C2100B7A0AB /* moc_technogymmyruntreadmill.cpp in Compile Sources */,
|
||||
8738249227E646E3004F1B46 /* characteristicnotifier2a63.cpp in Compile Sources */,
|
||||
8738249327E646E3004F1B46 /* characteristicwriteprocessor2ad9.cpp in Compile Sources */,
|
||||
@@ -3329,6 +3460,7 @@
|
||||
DF373364C5474D877506CB26 /* FitMesg.mm in Compile Sources */,
|
||||
872261F0289EA887006A6F75 /* moc_nordictrackelliptical.cpp in Compile Sources */,
|
||||
873824E327E647A8004F1B46 /* bitmap.cpp in Compile Sources */,
|
||||
876E510A2B70FDA30080FAAF /* zapCrypto.swift in Compile Sources */,
|
||||
87FE5BB12692F31E0056EFC8 /* moc_tacxneo2.cpp in Compile Sources */,
|
||||
873824E827E647A8004F1B46 /* provider.cpp in Compile Sources */,
|
||||
8791A8AA25C8603F003B50B2 /* moc_inspirebike.cpp in Compile Sources */,
|
||||
@@ -3373,6 +3505,7 @@
|
||||
87EFE45927A518F5006EA1C3 /* nautiluselliptical.cpp in Compile Sources */,
|
||||
E62DA5FF2436135448C94671 /* moc_toorxtreadmill.cpp in Compile Sources */,
|
||||
87586A4325B8341B00A243C4 /* moc_proformbike.cpp in Compile Sources */,
|
||||
876E51092B70FDA30080FAAF /* abstractZapDevice.swift in Compile Sources */,
|
||||
87CC3BA325A0885F001EC5A8 /* domyoselliptical.cpp in Compile Sources */,
|
||||
87D105542909971100B3935B /* moc_mepanelbike.cpp in Compile Sources */,
|
||||
87B617F325F260150094A1CB /* moc_snodebike.cpp in Compile Sources */,
|
||||
|
||||
1
src/ios/CryptoSwift
Submodule
1
src/ios/CryptoSwift
Submodule
Submodule src/ios/CryptoSwift added at 7892a123f7
@@ -74,6 +74,10 @@ class lockscreen {
|
||||
int zwift_api_getdistance();
|
||||
float zwift_api_getlatitude();
|
||||
float zwift_api_getlongitude();
|
||||
|
||||
// Zwift ZAP Device
|
||||
const char* zapDevice_buildHandshakeStart();
|
||||
int zapDevice_processCharacteristic(const char* data, int len);
|
||||
};
|
||||
|
||||
#endif // LOCKSCREEN_H
|
||||
|
||||
@@ -31,6 +31,8 @@ static ios_eliteariafan* ios_eliteAriaFan = nil;
|
||||
|
||||
static zwift_protobuf_layer* zwiftProtobufLayer = nil;
|
||||
|
||||
static ZwiftPlayDevice *zapDevice = nil;
|
||||
|
||||
void lockscreen::setTimerDisabled() {
|
||||
[[UIApplication sharedApplication] setIdleTimerDisabled: YES];
|
||||
}
|
||||
@@ -47,6 +49,11 @@ void lockscreen::request()
|
||||
if (@available(iOS 17, *)) {
|
||||
_adb = [[AdbClient alloc] initWithVerbose:YES];
|
||||
}
|
||||
|
||||
if (@available(iOS 14, *)) {
|
||||
zapDevice = [[ZwiftPlayDevice alloc] init];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
long lockscreen::heartRate()
|
||||
@@ -322,4 +329,19 @@ float lockscreen::zwift_api_getlatitude() {
|
||||
float lockscreen::zwift_api_getlongitude() {
|
||||
return [zwiftProtobufLayer getLongitude];
|
||||
}
|
||||
|
||||
const char* lockscreen::zapDevice_buildHandshakeStart() {
|
||||
if(zapDevice) {
|
||||
return (const char*)[[zapDevice buildHandshakeStart] bytes];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int lockscreen::zapDevice_processCharacteristic(const char* data, int len) {
|
||||
if(zapDevice) {
|
||||
NSData *d = [NSData dataWithBytes:data length:len];
|
||||
return [zapDevice processEncryptedDataWithBytes:d];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
63
src/ios/zwift_play/abstractZapDevice.swift
Normal file
63
src/ios/zwift_play/abstractZapDevice.swift
Normal file
@@ -0,0 +1,63 @@
|
||||
import Foundation
|
||||
import os.log
|
||||
|
||||
// Assuming Logger and extensions for Data to convert to hex string and to check prefix are defined elsewhere in your Swift project.
|
||||
extension Data {
|
||||
func toHexString() -> String {
|
||||
self.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
|
||||
func starts(with prefix: Data) -> Bool {
|
||||
self.prefix(prefix.count) == prefix
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
@objc class AbstractZapDevice: NSObject {
|
||||
private static let logRaw = true
|
||||
|
||||
private var devicePublicKeyBytes: Data?
|
||||
private let localKeyProvider = LocalKeyProvider()
|
||||
open var zapEncryption: ZapCrypto
|
||||
|
||||
override init() {
|
||||
self.zapEncryption = ZapCrypto(localKeyProvider: localKeyProvider)
|
||||
}
|
||||
|
||||
@objc func processCharacteristic(characteristicName: String, bytes: Data?) -> Int {
|
||||
guard let bytes = bytes else { return 0 }
|
||||
|
||||
if Self.logRaw {
|
||||
os_log("%{public}@ %{public}@", log: OSLog.default, type: .debug, characteristicName, bytes.toHexString())
|
||||
}
|
||||
|
||||
if bytes.starts(with: ZapConstants.rideOn + ZapConstants.responseStart) {
|
||||
processDevicePublicKeyResponse(bytes: bytes)
|
||||
} else if bytes.count > MemoryLayout<Int>.size + EncryptionUtils.macLength {
|
||||
return processEncryptedData(bytes: bytes)
|
||||
} else {
|
||||
// Logger equivalent in Swift
|
||||
os_log("Unprocessed - Data Type: %{public}@", log: OSLog.default, type: .error, bytes.toHexString())
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@objc func buildHandshakeStart() -> Data {
|
||||
return ZapConstants.rideOn + ZapConstants.requestStart + localKeyProvider.getPublicKeyBytes()
|
||||
}
|
||||
|
||||
private func processDevicePublicKeyResponse(bytes: Data) {
|
||||
let startIndex = ZapConstants.rideOn.count + ZapConstants.responseStart.count
|
||||
devicePublicKeyBytes = bytes.subdata(in: startIndex..<bytes.count)
|
||||
zapEncryption.initialise(devicePublicKeyBytes: devicePublicKeyBytes!)
|
||||
if Self.logRaw {
|
||||
// Logger equivalent in Swift
|
||||
os_log("Device Public Key - %{public}@", log: OSLog.default, type: .debug, devicePublicKeyBytes!.toHexString())
|
||||
}
|
||||
}
|
||||
|
||||
// Abstract method placeholder - Swift doesn't support abstract classes/methods directly, so this method should be overridden in subclass.
|
||||
func processEncryptedData(bytes: Data) -> Int {
|
||||
fatalError("This method should be overridden by subclasses")
|
||||
}
|
||||
}
|
||||
42
src/ios/zwift_play/encryptionUtils.swift
Normal file
42
src/ios/zwift_play/encryptionUtils.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
import Foundation
|
||||
import CryptoSwift
|
||||
import CryptoKit
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
struct EncryptionUtils {
|
||||
static let keyLength = 32
|
||||
static let hkdfLength = 36
|
||||
static let macLength = 4
|
||||
|
||||
// Converti una chiave pubblica EC in array di byte
|
||||
static func publicKeyToByteArray(publicKey: P256.KeyAgreement.PublicKey) -> Data {
|
||||
// Assumendo che `publicKey` sia una rappresentazione simile di CryptoKit's P256,
|
||||
// la conversione diretta alla rappresentazione di byte è già disponibile
|
||||
return publicKey.rawRepresentation
|
||||
}
|
||||
|
||||
// Genera una chiave pubblica EC dai byte ricevuti
|
||||
static func generatePublicKey(publicKeyBytes: Data) throws -> P256.KeyAgreement.PublicKey {
|
||||
// Assumendo l'uso di CryptoKit per la generazione della chiave pubblica
|
||||
return try P256.KeyAgreement.PublicKey(x963Representation: publicKeyBytes)
|
||||
}
|
||||
|
||||
// Genera byte di segreto condiviso
|
||||
static func generateSharedSecretBytes(privateKey: P256.KeyAgreement.PrivateKey, publicKey: P256.KeyAgreement.PublicKey) -> Data {
|
||||
let sharedSecret = try! privateKey.sharedSecretFromKeyAgreement(with: publicKey)
|
||||
// Direttamente in formato Data
|
||||
return sharedSecret.withUnsafeBytes { Data($0) }
|
||||
}
|
||||
|
||||
// Genera byte usando HKDF
|
||||
static func generateHKDFBytes(secretKey: Data, salt: Data, info: Data = Data(), outputByteCount: Int) -> Data? {
|
||||
do {
|
||||
let hkdf = try HKDF(password: secretKey.bytes, salt: salt.bytes, info: info.bytes, keyLength: outputByteCount, variant: .sha256)
|
||||
let derivedKey = try hkdf.calculate()
|
||||
return Data(derivedKey)
|
||||
} catch {
|
||||
print("Errore durante la derivazione HKDF: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/ios/zwift_play/localKeyProvider.swift
Normal file
36
src/ios/zwift_play/localKeyProvider.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
class LocalKeyProvider {
|
||||
private var keyPair: P256.KeyAgreement.PrivateKey?
|
||||
|
||||
init() {
|
||||
generateKeyPair()
|
||||
}
|
||||
|
||||
func getPublicKeyBytes() -> Data {
|
||||
guard let publicKey = keyPair?.publicKey else {
|
||||
fatalError("Key pair not initialized correctly.")
|
||||
}
|
||||
return publicKey.rawRepresentation
|
||||
}
|
||||
|
||||
func getPublicKey() -> P256.KeyAgreement.PublicKey {
|
||||
guard let publicKey = keyPair?.publicKey else {
|
||||
fatalError("Key pair not initialized correctly.")
|
||||
}
|
||||
return publicKey
|
||||
}
|
||||
|
||||
func getPrivateKey() -> P256.KeyAgreement.PrivateKey {
|
||||
guard let keyPair = keyPair else {
|
||||
fatalError("Key pair not initialized correctly.")
|
||||
}
|
||||
return keyPair
|
||||
}
|
||||
|
||||
private func generateKeyPair() {
|
||||
keyPair = P256.KeyAgreement.PrivateKey()
|
||||
}
|
||||
}
|
||||
14
src/ios/zwift_play/zapBleUuids.swift
Normal file
14
src/ios/zwift_play/zapBleUuids.swift
Normal file
@@ -0,0 +1,14 @@
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
|
||||
enum ZapBleUuids {
|
||||
// ZAP Service - Zwift Accessory Protocol
|
||||
static let zwiftCustomServiceUUID = CBUUID(string: "00000001-19CA-4651-86E5-FA29DCDD09D1")
|
||||
static let zwiftAsyncCharacteristicUUID = CBUUID(string: "00000002-19CA-4651-86E5-FA29DCDD09D1")
|
||||
static let zwiftSyncRxCharacteristicUUID = CBUUID(string: "00000003-19CA-4651-86E5-FA29DCDD09D1")
|
||||
static let zwiftSyncTxCharacteristicUUID = CBUUID(string: "00000004-19CA-4651-86E5-FA29DCDD09D1")
|
||||
// This doesn't appear in the real hardware but is found in the companion app code.
|
||||
// static let zwiftDebugCharacteristicUUID = CBUUID(string: "00000005-19CA-4651-86E5-FA29DCDD09D1")
|
||||
// I have not seen this characteristic used. Guess it could be for Device Firmware Update (DFU)? it is a chip from Nordic.
|
||||
static let zwiftUnknown6CharacteristicUUID = CBUUID(string: "00000006-19CA-4651-86E5-FA29DCDD09D1")
|
||||
}
|
||||
20
src/ios/zwift_play/zapConstants.swift
Normal file
20
src/ios/zwift_play/zapConstants.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
import Foundation
|
||||
|
||||
enum ZapConstants {
|
||||
static let zwiftManufacturerId = 2378 // Zwift, Inc
|
||||
static let rc1LeftSide: UInt8 = 3
|
||||
static let rc1RightSide: UInt8 = 2
|
||||
static let zwiftClick: UInt8 = 9
|
||||
|
||||
static let rideOn = Data([82, 105, 100, 101, 79, 110])
|
||||
|
||||
// these don't actually seem to matter, its just the header has to be 7 bytes RIDEON + 2
|
||||
static let requestStart = Data([0, 9]) //Data([1, 2])
|
||||
static let responseStart = Data([1, 3]) // from device
|
||||
|
||||
// Message types received from device
|
||||
static let controllerNotificationMessageType: UInt8 = 7
|
||||
static let emptyMessageType: UInt8 = 21
|
||||
static let batteryLevelType: UInt8 = 25
|
||||
static let clickType: UInt8 = 55
|
||||
}
|
||||
91
src/ios/zwift_play/zapCrypto.swift
Normal file
91
src/ios/zwift_play/zapCrypto.swift
Normal file
@@ -0,0 +1,91 @@
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
class ZapCrypto {
|
||||
private let localKeyProvider: LocalKeyProvider
|
||||
private var encryptionKeyBytes: Data?
|
||||
private var ivBytes: Data?
|
||||
private var counter: Int = 0
|
||||
|
||||
init(localKeyProvider: LocalKeyProvider) {
|
||||
self.localKeyProvider = localKeyProvider
|
||||
}
|
||||
|
||||
func initialise(devicePublicKeyBytes: Data) {
|
||||
let hkdfBytes: Data = generateHmacKeyDerivationFunctionBytes(devicePublicKeyBytes: devicePublicKeyBytes)
|
||||
self.encryptionKeyBytes = hkdfBytes.subdata(in: 0..<EncryptionUtils.keyLength)
|
||||
self.ivBytes = hkdfBytes.subdata(in: 32..<EncryptionUtils.hkdfLength)
|
||||
}
|
||||
|
||||
func encrypt(data: Data) -> Data? {
|
||||
guard let encryptionKeyBytes = encryptionKeyBytes, let ivBytes = ivBytes else {
|
||||
assertionFailure("Not initialised")
|
||||
return nil
|
||||
}
|
||||
|
||||
let counterValue = counter
|
||||
self.counter += 1
|
||||
|
||||
let nonceBytes: Data = createNonce(iv: ivBytes, messageCounter: counterValue)
|
||||
return encryptDecrypt(encrypt: true, nonceBytes: nonceBytes, data: data)?.prependCounter(counterValue)
|
||||
}
|
||||
|
||||
func decrypt(counterArray: Data, payload: Data) -> Data? {
|
||||
guard let ivBytes = ivBytes else {
|
||||
assertionFailure("Not initialised")
|
||||
return nil
|
||||
}
|
||||
|
||||
let nonceBytes: Data = ivBytes + counterArray
|
||||
return encryptDecrypt(encrypt: false, nonceBytes: nonceBytes, data: payload)
|
||||
}
|
||||
|
||||
private func encryptDecrypt(encrypt: Bool, nonceBytes: Data, data: Data) -> Data? {
|
||||
let encryptionKey = SymmetricKey(data: encryptionKeyBytes!)
|
||||
|
||||
let sealedBox: AES.GCM.SealedBox
|
||||
do {
|
||||
if encrypt {
|
||||
sealedBox = try AES.GCM.seal(data, using: encryptionKey, nonce: AES.GCM.Nonce(data: nonceBytes))
|
||||
} else {
|
||||
sealedBox = try AES.GCM.SealedBox(nonce: AES.GCM.Nonce(data: nonceBytes), ciphertext: data, tag: Data())
|
||||
return try AES.GCM.open(sealedBox, using: encryptionKey)
|
||||
}
|
||||
return sealedBox.ciphertext + sealedBox.tag
|
||||
} catch {
|
||||
print(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func generateHmacKeyDerivationFunctionBytes(devicePublicKeyBytes: Data) -> Data {
|
||||
do {
|
||||
let serverPublicKey = try EncryptionUtils.generatePublicKey(publicKeyBytes: devicePublicKeyBytes)
|
||||
let sharedSecretBytes = EncryptionUtils.generateSharedSecretBytes(privateKey: localKeyProvider.getPrivateKey(), publicKey: serverPublicKey)
|
||||
let salt = EncryptionUtils.publicKeyToByteArray(publicKey: serverPublicKey) + localKeyProvider.getPublicKeyBytes()
|
||||
return EncryptionUtils.generateHKDFBytes(secretKey: sharedSecretBytes, salt: salt, outputByteCount: EncryptionUtils.hkdfLength) ?? Data()
|
||||
} catch {
|
||||
print(error)
|
||||
return Data()
|
||||
}
|
||||
}
|
||||
|
||||
private func createNonce(iv: Data, messageCounter: Int) -> Data {
|
||||
return iv + createCounterBytes(messageCounter: messageCounter)
|
||||
}
|
||||
|
||||
private func createCounterBytes(messageCounter: Int) -> Data {
|
||||
var counterValue = messageCounter.bigEndian
|
||||
return Data(bytes: &counterValue, count: MemoryLayout.size(ofValue: counterValue))
|
||||
}
|
||||
}
|
||||
|
||||
extension Data {
|
||||
func prependCounter(_ counter: Int) -> Data {
|
||||
var counterValue = counter.bigEndian
|
||||
var data = Data(bytes: &counterValue, count: MemoryLayout.size(ofValue: counterValue))
|
||||
data.append(contentsOf: self)
|
||||
return data
|
||||
}
|
||||
}
|
||||
70
src/ios/zwift_play/zwiftPlayDevice.swift
Normal file
70
src/ios/zwift_play/zwiftPlayDevice.swift
Normal file
@@ -0,0 +1,70 @@
|
||||
import Foundation
|
||||
import os.log
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
@objc class ZwiftPlayDevice: AbstractZapDevice {
|
||||
private var batteryLevel = 0
|
||||
|
||||
@objc override func processEncryptedData(bytes: Data) -> Int {
|
||||
do {
|
||||
os_log("Decrypted: %{public}@", log: OSLog.default, type: .debug, bytes.toHexString())
|
||||
|
||||
if bytes.count < 5 {
|
||||
return 0
|
||||
}
|
||||
|
||||
let counter = bytes.prefix(4)
|
||||
let payload = bytes.suffix(from: 4)
|
||||
|
||||
guard let data = zapEncryption.decrypt(counterArray: counter, payload: payload) else {
|
||||
os_log("Decrypt failed", log: OSLog.default, type: .error)
|
||||
return 0
|
||||
}
|
||||
|
||||
let type = data[0]
|
||||
let message = data.suffix(from: 1)
|
||||
|
||||
switch type {
|
||||
case ZapConstants.controllerNotificationMessageType:
|
||||
os_log("controllerNotificationMessageType")
|
||||
//processButtonNotification(notification: ControllerNotification(data: message))
|
||||
case ZapConstants.clickType:
|
||||
return processClickButtonNotification(data: data)
|
||||
case ZapConstants.emptyMessageType:
|
||||
os_log("emptyMessageType")
|
||||
case ZapConstants.batteryLevelType:
|
||||
os_log("batteryLevelType")
|
||||
default:
|
||||
os_log("Unprocessed - Type: %{public}@ Data: %{public}@", log: OSLog.default, type: .error, String(describing: type), data.toHexString())
|
||||
}
|
||||
} catch {
|
||||
os_log("Decrypt failed: %{public}@", log: OSLog.default, type: .error, error.localizedDescription)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
/*
|
||||
private func processButtonNotification(notification: ControllerNotification) {
|
||||
if let lastButtonState = lastButtonState {
|
||||
let diff = notification.diff(lastButtonState: lastButtonState)
|
||||
if !diff.isEmpty {
|
||||
os_log("%{public}@", log: OSLog.default, type: .debug, diff)
|
||||
}
|
||||
} else {
|
||||
os_log("%{public}@", log: OSLog.default, type: .debug, notification.description)
|
||||
}
|
||||
lastButtonState = notification
|
||||
}*/
|
||||
|
||||
private func processClickButtonNotification(data: Data) -> Int {
|
||||
if data.count == 5 {
|
||||
if data[4] == 0 {
|
||||
os_log("Click '-' Button Press", log: OSLog.default, type: .debug)
|
||||
return 2
|
||||
} else if data[2] == 0 {
|
||||
os_log("Click '+' Button Press", log: OSLog.default, type: .debug)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QAndroidJniObject>
|
||||
#include <QAndroidJniEnvironment>
|
||||
#elif defined Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
#endif
|
||||
|
||||
class AbstractZapDevice: public QObject {
|
||||
@@ -24,6 +26,12 @@ public:
|
||||
RIDE_ON = QByteArray::fromRawData("\x52\x69\x64\x65\x4F\x6E", 6); // "RideOn"
|
||||
REQUEST_START = QByteArray::fromRawData("\x00\x09", 2); // {0, 9}
|
||||
RESPONSE_START = QByteArray::fromRawData("\x01\x03", 2); // {1, 3}
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
h = new lockscreen();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int processCharacteristic(const QString& characteristicName, const QByteArray& bytes) {
|
||||
@@ -31,6 +39,7 @@ public:
|
||||
|
||||
qDebug() << characteristicName << bytes.toHex();
|
||||
|
||||
int button = 0;
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniEnvironment env;
|
||||
jbyteArray d = env->NewByteArray(bytes.length());
|
||||
@@ -39,16 +48,17 @@ public:
|
||||
b[i] = bytes[i];
|
||||
env->SetByteArrayRegion(d, 0, bytes.length(), b);
|
||||
|
||||
int button = QAndroidJniObject::callStaticMethod<int>(
|
||||
button = QAndroidJniObject::callStaticMethod<int>(
|
||||
"org/cagnulen/qdomyoszwift/ZapClickLayer", "processCharacteristic", "([B)I", d);
|
||||
env->DeleteLocalRef(d);
|
||||
#elif defined Q_OS_IOS
|
||||
button = h->zapDevice_processCharacteristic(bytes, bytes.length());
|
||||
#endif
|
||||
if(button == 1)
|
||||
emit plus();
|
||||
else if(button == 2)
|
||||
emit minus();
|
||||
return button;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
QByteArray buildHandshakeStart() {
|
||||
@@ -71,6 +81,8 @@ public:
|
||||
// Ora puoi usare byteArray come necessario
|
||||
return byteArray;
|
||||
}
|
||||
#elif defined Q_OS_IOS
|
||||
return h->zapDevice_buildHandshakeStart();
|
||||
#endif
|
||||
//return RIDE_ON + REQUEST_START + localKeyProvider.getPublicKeyBytes();
|
||||
return QByteArray();
|
||||
@@ -80,6 +92,9 @@ protected:
|
||||
virtual void processEncryptedData(const QByteArray& bytes) = 0;
|
||||
|
||||
private:
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
#endif
|
||||
QByteArray devicePublicKeyBytes;
|
||||
|
||||
signals:
|
||||
|
||||
Reference in New Issue
Block a user