Compare commits

...

26 Commits

Author SHA1 Message Date
spidy123222
625389ab96 Add Exit Shortcut 2025-04-08 15:19:33 -07:00
spidy123222
f7e34cbbe9 Rewrite SendAppOperation execution to allow to wait for shortcut execution. 2025-04-08 15:19:33 -07:00
spidy123222
0fe8d7fed9 Move to SendAppOperation 2025-04-08 15:19:33 -07:00
spidy123222
1a1aa42e02 move it behind pendiungunitcount 60 2025-04-08 15:19:33 -07:00
spidy123222
7ff4b48223 Move attempt to a higher Stage. 2025-04-08 15:19:33 -07:00
spidy123222
4801f6e8f2 Attempt a million 2025-04-08 15:19:33 -07:00
Spidy123222
ff28f6fa8f Add files via upload
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
2d141afbaf remove from install apps
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
06e38aae00 Hopefully fix problem
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
d8783230a7 fix error for open link
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
Spidy123222
6c479bfede test open URL
Signed-off-by: Spidy123222 <64176728+Spidy123222@users.noreply.github.com>
2025-04-08 15:19:33 -07:00
polymo1
591913743e Merge pull request #940 from Br0des/develop
Added StosVPN to the EM Proxy part.
2025-04-05 22:38:53 -04:00
Brodes
77d95fe278 Added StosVPN to the EM Proxy part.
yeah i'm petty >:3

Signed-off-by: Brodes <144500576+Br0des@users.noreply.github.com>
2025-04-05 20:13:07 -06:00
Joseph LaFreniere
0cd62d371a [Skip Ci] Fix typo "levaraging" -> "leveraging" (#926)
Signed-off-by: Joseph LaFreniere <git@lafreniere.xyz>
2025-03-31 15:12:25 -07:00
Magesh K
9771f6bb9a Merge pull request #920 from mahee96/develop
Migration: Fixes for migration issues when migrating from 0.5.9 to 0.6.0
2025-03-25 20:37:16 -07:00
mahee96
e553efbad5 - migration-fix: more reinforcements for 0.6.0 to 0.6.1 2025-03-24 01:32:01 -07:00
mahee96
a4dfd28a3c - [Fix]: migrations fix for coredata from v11(0.5.9) to v17_1(0.6.1) and v17(0.6.0 to v17_1(0.6.1) 2025-03-24 00:19:05 -07:00
mahee96
a7496e08e3 - [WIP]: migrations fix for coredata from v11(0.5.9) to v17_1(0.6.1) and v17(0.6.0 to v17_1(0.6.1) 2025-03-23 12:09:58 -07:00
mahee96
2f3be07b5d - fix: attempt to fix "app no longer available" issues due to fetch profiles not updating appFeatures and appGroups (possible regression from PR#846) 2025-03-23 12:00:31 -07:00
mahee96
cbde3e6495 Revert "- Fixed: attempt migrations fix from 0.5.10 to 0.6.0"
This reverts commit ae8e9a3506.
2025-03-23 11:57:16 -07:00
polymo1
117f31e158 Merge pull request #915 from neoarz/patch-3
Update SettingsViewController.swift
2025-03-15 10:13:42 -04:00
neoarz
420efcbb11 Update SettingsViewController.swift
Signed-off-by: neoarz <164915254+neoarz@users.noreply.github.com>
2025-03-15 06:30:03 -04:00
mahee96
ae8e9a3506 - Fixed: attempt migrations fix from 0.5.10 to 0.6.0 2025-03-11 04:44:23 +05:30
Magesh K
3785891923 Merge pull request #900 from l2dy/patch-1
fix: typo in hasUpdate comparison
2025-03-04 03:33:32 +05:30
Zero King
e85db67ac7 fix: typo in hasUpdate comparison
Signed-off-by: Zero King <l2dy@icloud.com>
2025-03-02 01:47:04 +08:00
mahee96
39d0835f5b - CI: updated stable.yml for recent fixes 2025-03-01 01:30:15 +05:30
34 changed files with 3379 additions and 173 deletions

View File

@@ -7,73 +7,268 @@ on:
jobs: jobs:
build: build:
name: Build and upload SideStore name: Build SideStore - stable (on tag push)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: 'macos-14' - os: 'macos-15'
version: '15.4' version: '16.2'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Install dependencies - name: Echo Build.xcconfig
run: brew install ldid run: |
echo "cat Build.xcconfig"
cat Build.xcconfig
shell: bash
- name: Change version to tag # - name: Change MARKETING_VERSION to the pushed tag that triggered this build
run: sed -e '/MARKETING_VERSION = .*/s/= .*/= ${{ github.ref_name }}/' -i '' Build.xcconfig # run: sed -e '/MARKETING_VERSION = .*/s/= .*/= ${{ github.ref_name }}/' -i '' Build.xcconfig
- name: Get version - name: Echo Updated Build.xcconfig
run: |
cat Build.xcconfig
shell: bash
- name: Extract MARKETING_VERSION from Build.xcconfig
id: version id: version
run: echo "version=$(grep MARKETING_VERSION Build.xcconfig | sed -e "s/MARKETING_VERSION = //g")" >> $GITHUB_OUTPUT run: |
version=$(grep MARKETING_VERSION Build.xcconfig | sed -e 's/MARKETING_VERSION = //g')
echo "version=$version" >> $GITHUB_OUTPUT
echo "version=$version"
- name: Echo version echo "MARKETING_VERSION=$version" >> $GITHUB_ENV
run: echo "${{ steps.version.outputs.version }}" echo "MARKETING_VERSION=$version" >> $GITHUB_OUTPUT
echo "MARKETING_VERSION=$version"
shell: bash
- name: Fail the build if pushed tag and embedded MARKETING_VERSION in Build.xcconfig are mismatching
run: |
if [ "$MARKETING_VERSION" != "${{ github.ref_name }}" ]; then
echo 'Version mismatch: $tag != $marketing_version ... '
echo " expected-tag : $MARKETING_VERSION"
echo " pushed-tag : ${{ github.ref_name }}"
exit 1
fi
echo 'Version matches: $tag == $marketing_version ... '
echo " expected-tag : $MARKETING_VERSION"
echo " pushed-tag : ${{ github.ref_name }}"
shell: bash
- name: Install dependencies - ldid & xcbeautify
run: |
brew install ldid xcbeautify
- name: Setup Xcode - name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1.6.0 uses: maxim-lobanov/setup-xcode@v1.6.0
with: with:
xcode-version: ${{ matrix.version }} xcode-version: ${{ matrix.version }}
- name: Cache Build - name: (Build) Restore Xcode & SwiftPM Cache (Exact match)
uses: irgaly/xcode-cache@v1 id: xcode-cache-restore
uses: actions/cache/restore@v3
with: with:
key: xcode-cache-deriveddata-${{ github.sha }} path: |
restore-keys: xcode-cache-deriveddata- ~/Library/Developer/Xcode/DerivedData
swiftpm-cache-key: xcode-cache-sourcedata-${{ github.sha }} ~/Library/Caches/org.swift.swiftpm
swiftpm-cache-restore-keys: | key: xcode-cache-build-stable-${{ github.sha }}
xcode-cache-sourcedata-
- name: Build SideStore - name: (Build) Restore Xcode & SwiftPM Cache (Last Available)
run: NSUnbufferedIO=YES make build | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]} id: xcode-cache-restore-recent
uses: actions/cache/restore@v3
with:
path: |
~/Library/Developer/Xcode/DerivedData
~/Library/Caches/org.swift.swiftpm
key: xcode-cache-build-stable-
- name: (Build) Restore Pods from Cache (Exact match)
id: pods-restore
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-stable-${{ hashFiles('Podfile') }}
- name: (Build) Restore Pods from Cache (Last Available)
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
id: pods-restore-recent
uses: actions/cache/restore@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-stable-
- name: (Build) Install CocoaPods
run: pod install
shell: bash
- name: (Build) Save Pods to Cache
id: save-pods
if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
./Podfile.lock
./Pods/
./AltStore.xcworkspace/
key: pods-cache-build-stable-${{ hashFiles('Podfile') }}
- name: (Build) Clean previous build artifacts
run: |
make clean
mkdir -p build/logs
shell: bash
- name: (Build) List Files and derived data
if: always()
shell: bash
run: |
echo ">>>>>>>>> Workdir <<<<<<<<<<"
ls -la .
echo ""
echo ">>>>>>>>> Pods <<<<<<<<<<"
find Pods -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> Dependencies <<<<<<<<<<"
find Dependencies -maxdepth 2 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<"
ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists
echo ""
- name: Build SideStore.xcarchive
# using 'tee' to intercept stdout and log for detailed build-log
run: |
NSUnbufferedIO=YES make -B build 2>&1 | tee -a build/logs/build.log | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}
shell: bash
- name: Fakesign app - name: Fakesign app
run: make fakesign run: make fakesign | tee -a build/logs/build.log
shell: bash
- name: Convert to IPA - name: Convert to IPA
run: make ipa run: make ipa | tee -a build/logs/build.log
shell: bash
- name: (Build) Save Xcode & SwiftPM Cache
id: cache-save
if: ${{ steps.xcode-cache-restore.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: |
~/Library/Developer/Xcode/DerivedData
~/Library/Caches/org.swift.swiftpm
key: xcode-cache-build-stable-${{ github.sha }}
- name: (Build) List Files and Build artifacts
run: |
echo ">>>>>>>>> Workdir <<<<<<<<<<"
ls -la .
echo ""
echo ">>>>>>>>> Build <<<<<<<<<<"
find build -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore <<<<<<<<<<"
find SideStore -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> SideStore.xcarchive <<<<<<<<<<"
find SideStore.xcarchive -maxdepth 3 -exec ls -ld {} + || true # List contents if directory exists
echo ""
echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<"
ls -la ~/Library/Developer/Xcode/DerivedData || true # List contents if directory exists
echo ""
shell: bash
- name: Encrypt build-logs for upload
id: encrypt-build-log
run: |
DEFAULT_BUILD_LOG_PASSWORD=12345
BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }}
BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD}
if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then
echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'."
fi
pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-build-logs.zip * || popd
echo "::set-output name=encrypted::true"
shell: bash
- name: Upload encrypted-build-logs.zip
id: attach-encrypted-build-log
if: ${{ always() && steps.encrypt-build-log.outputs.encrypted == 'true' }}
uses: actions/upload-artifact@v4
with:
name: encrypted-build-logs-${{ steps.version.outputs.version }}.zip
path: encrypted-build-logs.zip
- name: Upload SideStore.ipa Artifact
uses: actions/upload-artifact@v4
with:
name: SideStore-${{ steps.version.outputs.version }}.ipa
path: SideStore.ipa
- name: Zip dSYMs
run: zip -r -9 ./SideStore.dSYMs.zip ./SideStore.xcarchive/dSYMs
shell: bash
- name: Upload *.dSYM Artifact
uses: actions/upload-artifact@v4
with:
name: SideStore-${{ steps.version.outputs.version }}-dSYMs.zip
path: SideStore.dSYMs.zip
- name: Get current date - name: Get current date
id: date id: date
run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT
shell: bash
- name: Get current date in AltStore date form - name: Get current date in AltStore date form
id: date_altstore id: date_altstore
run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT
shell: bash
- name: Upload to new stable release - name: Upload to releases
uses: softprops/action-gh-release@v1 uses: IsaacShelton/update-existing-release@v1.3.1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ steps.version.outputs.version }}
tag_name: ${{ github.ref_name }}
draft: true draft: true
files: SideStore.ipa release: ${{ github.ref_name }} # name
tag: ${{ github.ref_name }}
# stick with what the user pushed, do not use latest commit or anything,
# ex: if we want to go back to previous release due to hot issue, dev can create a new tag pointing to that older working tag/commit so as to keep it as an update (to revert major issue)
# in this case we do not want the tag to be auto-updated to latest
updateTag: false
prerelease: false
files: >
SideStore.ipa
SideStore.dSYMs.zip
encrypted-build-logs.zip
body: | body: |
<!-- NOTE: to reset SideSource cache, go to `https://apps.sidestore.io/reset-cache/nightly/<sidesource key>`. This is not included in the GitHub Action since it makes draft releases so they can be edited and have a changelog. --> <!-- NOTE: to reset SideSource cache, go to `https://apps.sidestore.io/reset-cache/nightly/<sidesource key>`. This is not included in the GitHub Action since it makes draft releases so they can be edited and have a changelog. -->
## Changelog ## Changelog
@@ -86,18 +281,3 @@ jobs:
Built at (UTC date): `${{ steps.date_altstore.outputs.date }}` Built at (UTC date): `${{ steps.date_altstore.outputs.date }}`
Commit SHA: `${{ github.sha }}` Commit SHA: `${{ github.sha }}`
Version: `${{ steps.version.outputs.version }}` Version: `${{ steps.version.outputs.version }}`
- name: Add version to IPA file name
run: mv SideStore.ipa SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload SideStore.ipa Artifact
uses: actions/upload-artifact@v4
with:
name: SideStore-${{ steps.version.outputs.version }}.ipa
path: SideStore-${{ steps.version.outputs.version }}.ipa
- name: Upload *.dSYM Artifact
uses: actions/upload-artifact@v4
with:
name: SideStore-${{ steps.version.outputs.version }}-dSYM
path: ./*.dSYM/

View File

@@ -59,6 +59,15 @@
A80D60D32D3DD85100CEF65D /* ReleaseTrack.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D60D12D3D705F00CEF65D /* ReleaseTrack.swift */; }; A80D60D32D3DD85100CEF65D /* ReleaseTrack.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D60D12D3D705F00CEF65D /* ReleaseTrack.swift */; };
A80D790D2D2F20AF00A40F40 /* PaginationIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D790C2D2F20AF00A40F40 /* PaginationIntent.swift */; }; A80D790D2D2F20AF00A40F40 /* PaginationIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D790C2D2F20AF00A40F40 /* PaginationIntent.swift */; };
A80D790F2D2F217000A40F40 /* PaginationDataHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D790E2D2F217000A40F40 /* PaginationDataHolder.swift */; }; A80D790F2D2F217000A40F40 /* PaginationDataHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D790E2D2F217000A40F40 /* PaginationDataHolder.swift */; };
A815AA952D90D2A100929A9E /* StoreApp17To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AA942D90D2A100929A9E /* StoreApp17To17_1MigrationPolicy.swift */; };
A815AA972D90E16400929A9E /* ReleaseTrack17To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AA962D90E16400929A9E /* ReleaseTrack17To17_1MigrationPolicy.swift */; };
A815AA992D90E5E500929A9E /* AltStore17ToAltStore17_1.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = A815AA982D90E5E500929A9E /* AltStore17ToAltStore17_1.xcmappingmodel */; };
A815AA9F2D9104DD00929A9E /* BuildInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AA9E2D9104DD00929A9E /* BuildInfo.swift */; };
A815AAA12D9108BC00929A9E /* AltStore11ToAltStore17_1.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = A815AAA02D9108BC00929A9E /* AltStore11ToAltStore17_1.xcmappingmodel */; };
A815AAA72D9108CB00929A9E /* ReleaseTrack11To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AAA42D9108CB00929A9E /* ReleaseTrack11To17_1MigrationPolicy.swift */; };
A815AAA82D9108CB00929A9E /* AppPermission11To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AAA52D9108CB00929A9E /* AppPermission11To17_1MigrationPolicy.swift */; };
A815AAA92D9108CB00929A9E /* Source11To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AAA22D9108CB00929A9E /* Source11To17_1MigrationPolicy.swift */; };
A815AAAA2D9108CB00929A9E /* StoreApp11To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A815AAA32D9108CB00929A9E /* StoreApp11To17_1MigrationPolicy.swift */; };
A81A8CB92D68B30B0086C96F /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; }; A81A8CB92D68B30B0086C96F /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; };
A81A8CBA2D68B3110086C96F /* TreeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81A8CB02D68B0320086C96F /* TreeMap.swift */; }; A81A8CBA2D68B3110086C96F /* TreeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81A8CB02D68B0320086C96F /* TreeMap.swift */; };
A81A8CBD2D68B43F0086C96F /* LinkedHashMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81A8CBC2D68B43F0086C96F /* LinkedHashMap.swift */; }; A81A8CBD2D68B43F0086C96F /* LinkedHashMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81A8CBC2D68B43F0086C96F /* LinkedHashMap.swift */; };
@@ -69,6 +78,8 @@
A81A8CD12D68BA9B0086C96F /* TreeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81A8CB02D68B0320086C96F /* TreeMap.swift */; }; A81A8CD12D68BA9B0086C96F /* TreeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81A8CB02D68B0320086C96F /* TreeMap.swift */; };
A81A8CD22D68BAA30086C96F /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; }; A81A8CD22D68BAA30086C96F /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; };
A81A8CD42D68BAFF0086C96F /* DataStructureTests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = A81A8CD32D68BAFF0086C96F /* DataStructureTests.xctestplan */; }; A81A8CD42D68BAFF0086C96F /* DataStructureTests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = A81A8CD32D68BAFF0086C96F /* DataStructureTests.xctestplan */; };
A81BF9E52D84CB0C00768940 /* AppPermission17To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81BF9E22D84CB0C00768940 /* AppPermission17To17_1MigrationPolicy.swift */; };
A81BF9E72D84CB0C00768940 /* Source17To17_1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81BF9E32D84CB0C00768940 /* Source17To17_1MigrationPolicy.swift */; };
A82067842D03DC0600645C0D /* OperatingSystemVersion+Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */; }; A82067842D03DC0600645C0D /* OperatingSystemVersion+Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */; };
A82067C42D03E0DE00645C0D /* SemanticVersion in Frameworks */ = {isa = PBXBuildFile; productRef = A82067C32D03E0DE00645C0D /* SemanticVersion */; }; A82067C42D03E0DE00645C0D /* SemanticVersion in Frameworks */ = {isa = PBXBuildFile; productRef = A82067C32D03E0DE00645C0D /* SemanticVersion */; };
A8228B5B2D6E2C0C00F7CE0E /* (null) in Sources */ = {isa = PBXBuildFile; }; A8228B5B2D6E2C0C00F7CE0E /* (null) in Sources */ = {isa = PBXBuildFile; };
@@ -77,7 +88,6 @@
A859ED5D2D1EE827003DCC58 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; A859ED5D2D1EE827003DCC58 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A86315DF2D3EB2DE0048FA40 /* ErrorProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */; }; A86315DF2D3EB2DE0048FA40 /* ErrorProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */; };
A8696EE42D34512C00E96389 /* RemoveAppExtensionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */; }; A8696EE42D34512C00E96389 /* RemoveAppExtensionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */; };
A881E7C72D6EF58C00954AD2 /* AltStore11ToAltStore17.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = A881E7C62D6EF58C00954AD2 /* AltStore11ToAltStore17.xcmappingmodel */; };
A881E7CB2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A881E7CA2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift */; }; A881E7CB2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A881E7CA2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift */; };
A88B8C492D35AD3200F53F9D /* OperationsLoggingContolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */; }; A88B8C492D35AD3200F53F9D /* OperationsLoggingContolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */; };
A88B8C552D35F1EC00F53F9D /* OperationsLoggingControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */; }; A88B8C552D35F1EC00F53F9D /* OperationsLoggingControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */; };
@@ -103,6 +113,7 @@
A8C6D5142D1EE8D700DF01F1 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; A8C6D5142D1EE8D700DF01F1 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A8C6D5172D1EE95B00DF01F1 /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; }; A8C6D5172D1EE95B00DF01F1 /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; };
A8C6D5182D1EE95B00DF01F1 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; A8C6D5182D1EE95B00DF01F1 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A8C924242D8E73B1009D9953 /* AltStore11ToAltStore17.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = A8C924232D8E73B1009D9953 /* AltStore11ToAltStore17.xcmappingmodel */; };
A8D484D82D0CD306002C691D /* AltBackup.ipa in Resources */ = {isa = PBXBuildFile; fileRef = A8D484D72D0CD306002C691D /* AltBackup.ipa */; }; A8D484D82D0CD306002C691D /* AltBackup.ipa in Resources */ = {isa = PBXBuildFile; fileRef = A8D484D72D0CD306002C691D /* AltBackup.ipa */; };
A8D49F532D3D2F9400844B92 /* ProcessInfo+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D49F522D3D2F9400844B92 /* ProcessInfo+AltStore.swift */; }; A8D49F532D3D2F9400844B92 /* ProcessInfo+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D49F522D3D2F9400844B92 /* ProcessInfo+AltStore.swift */; };
A8E2DB312D684E2A009E5D31 /* UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8E2DB2E2D684E2A009E5D31 /* UITests.swift */; }; A8E2DB312D684E2A009E5D31 /* UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8E2DB2E2D684E2A009E5D31 /* UITests.swift */; };
@@ -660,6 +671,15 @@
A80D60D12D3D705F00CEF65D /* ReleaseTrack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseTrack.swift; sourceTree = "<group>"; }; A80D60D12D3D705F00CEF65D /* ReleaseTrack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseTrack.swift; sourceTree = "<group>"; };
A80D790C2D2F20AF00A40F40 /* PaginationIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationIntent.swift; sourceTree = "<group>"; }; A80D790C2D2F20AF00A40F40 /* PaginationIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationIntent.swift; sourceTree = "<group>"; };
A80D790E2D2F217000A40F40 /* PaginationDataHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationDataHolder.swift; sourceTree = "<group>"; }; A80D790E2D2F217000A40F40 /* PaginationDataHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationDataHolder.swift; sourceTree = "<group>"; };
A815AA942D90D2A100929A9E /* StoreApp17To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreApp17To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A815AA962D90E16400929A9E /* ReleaseTrack17To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseTrack17To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A815AA982D90E5E500929A9E /* AltStore17ToAltStore17_1.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore17ToAltStore17_1.xcmappingmodel; sourceTree = "<group>"; };
A815AA9E2D9104DD00929A9E /* BuildInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildInfo.swift; sourceTree = "<group>"; };
A815AAA02D9108BC00929A9E /* AltStore11ToAltStore17_1.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore11ToAltStore17_1.xcmappingmodel; sourceTree = "<group>"; };
A815AAA22D9108CB00929A9E /* Source11To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Source11To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A815AAA32D9108CB00929A9E /* StoreApp11To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreApp11To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A815AAA42D9108CB00929A9E /* ReleaseTrack11To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseTrack11To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A815AAA52D9108CB00929A9E /* AppPermission11To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPermission11To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A81A8CB02D68B0320086C96F /* TreeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeMap.swift; sourceTree = "<group>"; }; A81A8CB02D68B0320086C96F /* TreeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeMap.swift; sourceTree = "<group>"; };
A81A8CB42D68B2180086C96F /* TreeMapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeMapTests.swift; sourceTree = "<group>"; }; A81A8CB42D68B2180086C96F /* TreeMapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeMapTests.swift; sourceTree = "<group>"; };
A81A8CBC2D68B43F0086C96F /* LinkedHashMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedHashMap.swift; sourceTree = "<group>"; }; A81A8CBC2D68B43F0086C96F /* LinkedHashMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkedHashMap.swift; sourceTree = "<group>"; };
@@ -667,6 +687,9 @@
A81A8CC52D68BA610086C96F /* DataStructureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DataStructureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A81A8CC52D68BA610086C96F /* DataStructureTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DataStructureTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A81A8CC72D68BA610086C96F /* DataStructuresTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStructuresTests.swift; sourceTree = "<group>"; }; A81A8CC72D68BA610086C96F /* DataStructuresTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStructuresTests.swift; sourceTree = "<group>"; };
A81A8CD32D68BAFF0086C96F /* DataStructureTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = DataStructureTests.xctestplan; sourceTree = "<group>"; }; A81A8CD32D68BAFF0086C96F /* DataStructureTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = DataStructureTests.xctestplan; sourceTree = "<group>"; };
A81BF9E12D84C9E900768940 /* AltStore 17_1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 17_1.xcdatamodel"; sourceTree = "<group>"; };
A81BF9E22D84CB0C00768940 /* AppPermission17To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPermission17To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A81BF9E32D84CB0C00768940 /* Source17To17_1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Source17To17_1MigrationPolicy.swift; sourceTree = "<group>"; };
A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:67RAULRX93:Marcin Krzyzanowski"; lastKnownFileType = wrapper.xcframework; name = OpenSSL.xcframework; path = SideStore/AltSign/Dependencies/OpenSSL/Frameworks/OpenSSL.xcframework; sourceTree = "<group>"; }; A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:67RAULRX93:Marcin Krzyzanowski"; lastKnownFileType = wrapper.xcframework; name = OpenSSL.xcframework; path = SideStore/AltSign/Dependencies/OpenSSL/Frameworks/OpenSSL.xcframework; sourceTree = "<group>"; };
A85ACB8E2D1F31C400AA3DE7 /* AltBackup.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltBackup.xcconfig; sourceTree = "<group>"; }; A85ACB8E2D1F31C400AA3DE7 /* AltBackup.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltBackup.xcconfig; sourceTree = "<group>"; };
A85ACB8F2D1F31C400AA3DE7 /* AltStore.debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStore.debug.xcconfig; sourceTree = "<group>"; }; A85ACB8F2D1F31C400AA3DE7 /* AltStore.debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStore.debug.xcconfig; sourceTree = "<group>"; };
@@ -679,7 +702,6 @@
A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorProcessing.swift; sourceTree = "<group>"; }; A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorProcessing.swift; sourceTree = "<group>"; };
A868CFE32D319988002F1201 /* SingletonGenericMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonGenericMap.swift; sourceTree = "<group>"; }; A868CFE32D319988002F1201 /* SingletonGenericMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonGenericMap.swift; sourceTree = "<group>"; };
A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppExtensionsOperation.swift; sourceTree = "<group>"; }; A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppExtensionsOperation.swift; sourceTree = "<group>"; };
A881E7C62D6EF58C00954AD2 /* AltStore11ToAltStore17.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore11ToAltStore17.xcmappingmodel; sourceTree = "<group>"; };
A881E7CA2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreApp11To17MigrationPolicy.swift; sourceTree = "<group>"; }; A881E7CA2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreApp11To17MigrationPolicy.swift; sourceTree = "<group>"; };
A881E8562D6FBBAF00954AD2 /* DataStructureTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DataStructureTests.xcconfig; sourceTree = "<group>"; }; A881E8562D6FBBAF00954AD2 /* DataStructureTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DataStructureTests.xcconfig; sourceTree = "<group>"; };
A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingContolView.swift; sourceTree = "<group>"; }; A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingContolView.swift; sourceTree = "<group>"; };
@@ -696,6 +718,7 @@
A8C38C2B2D206AD900E83DBD /* AbstractClassError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractClassError.swift; sourceTree = "<group>"; }; A8C38C2B2D206AD900E83DBD /* AbstractClassError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractClassError.swift; sourceTree = "<group>"; };
A8C38C312D206B2500E83DBD /* FileOutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileOutputStream.swift; sourceTree = "<group>"; }; A8C38C312D206B2500E83DBD /* FileOutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileOutputStream.swift; sourceTree = "<group>"; };
A8C38C372D2084D000E83DBD /* ConsoleLogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleLogView.swift; sourceTree = "<group>"; }; A8C38C372D2084D000E83DBD /* ConsoleLogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleLogView.swift; sourceTree = "<group>"; };
A8C924232D8E73B1009D9953 /* AltStore11ToAltStore17.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore11ToAltStore17.xcmappingmodel; sourceTree = "<group>"; };
A8D484D72D0CD306002C691D /* AltBackup.ipa */ = {isa = PBXFileReference; lastKnownFileType = file; path = AltBackup.ipa; sourceTree = "<group>"; }; A8D484D72D0CD306002C691D /* AltBackup.ipa */ = {isa = PBXFileReference; lastKnownFileType = file; path = AltBackup.ipa; sourceTree = "<group>"; };
A8D49F522D3D2F9400844B92 /* ProcessInfo+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+AltStore.swift"; sourceTree = "<group>"; }; A8D49F522D3D2F9400844B92 /* ProcessInfo+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+AltStore.swift"; sourceTree = "<group>"; };
A8E2DB212D684CBD009E5D31 /* UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A8E2DB212D684CBD009E5D31 /* UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1246,6 +1269,17 @@
path = Intents; path = Intents;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
A815AAA62D9108CB00929A9E /* v11-to-v17_1 */ = {
isa = PBXGroup;
children = (
A815AAA22D9108CB00929A9E /* Source11To17_1MigrationPolicy.swift */,
A815AAA32D9108CB00929A9E /* StoreApp11To17_1MigrationPolicy.swift */,
A815AAA42D9108CB00929A9E /* ReleaseTrack11To17_1MigrationPolicy.swift */,
A815AAA52D9108CB00929A9E /* AppPermission11To17_1MigrationPolicy.swift */,
);
path = "v11-to-v17_1";
sourceTree = "<group>";
};
A81A8CB22D68B2030086C96F /* UnitTests */ = { A81A8CB22D68B2030086C96F /* UnitTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1281,6 +1315,26 @@
path = xcconfigs; path = xcconfigs;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
A85E43732D8AF82100E89240 /* v11-to-v17 */ = {
isa = PBXGroup;
children = (
D5185B812AE1E71D00646E33 /* Source11To17MigrationPolicy.swift */,
A881E7CA2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift */,
);
path = "v11-to-v17";
sourceTree = "<group>";
};
A85E43742D8AF84200E89240 /* v17-to-v17_1 */ = {
isa = PBXGroup;
children = (
A81BF9E32D84CB0C00768940 /* Source17To17_1MigrationPolicy.swift */,
A815AA942D90D2A100929A9E /* StoreApp17To17_1MigrationPolicy.swift */,
A815AA962D90E16400929A9E /* ReleaseTrack17To17_1MigrationPolicy.swift */,
A81BF9E22D84CB0C00768940 /* AppPermission17To17_1MigrationPolicy.swift */,
);
path = "v17-to-v17_1";
sourceTree = "<group>";
};
A86315DD2D3EB2BD0048FA40 /* errors */ = { A86315DD2D3EB2BD0048FA40 /* errors */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1393,6 +1447,7 @@
A8C38C272D206AA500E83DBD /* common */ = { A8C38C272D206AA500E83DBD /* common */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A815AA9E2D9104DD00929A9E /* BuildInfo.swift */,
A8B516E52D2668020047047C /* DateTimeUtil.swift */, A8B516E52D2668020047047C /* DateTimeUtil.swift */,
A8C38C282D206AC100E83DBD /* OutputStream.swift */, A8C38C282D206AC100E83DBD /* OutputStream.swift */,
A8C38C312D206B2500E83DBD /* FileOutputStream.swift */, A8C38C312D206B2500E83DBD /* FileOutputStream.swift */,
@@ -1821,10 +1876,11 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BF66EEAF2501AECA007EE018 /* InstalledAppPolicy.swift */, BF66EEAF2501AECA007EE018 /* InstalledAppPolicy.swift */,
D5185B812AE1E71D00646E33 /* Source11To17MigrationPolicy.swift */,
BF66EEAE2501AECA007EE018 /* StoreAppPolicy.swift */, BF66EEAE2501AECA007EE018 /* StoreAppPolicy.swift */,
D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */, D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */,
A881E7CA2D6EF5AB00954AD2 /* StoreApp11To17MigrationPolicy.swift */, A85E43732D8AF82100E89240 /* v11-to-v17 */,
A85E43742D8AF84200E89240 /* v17-to-v17_1 */,
A815AAA62D9108CB00929A9E /* v11-to-v17_1 */,
); );
path = Policies; path = Policies;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1832,7 +1888,9 @@
BF66EEB02501AECA007EE018 /* Mapping Models */ = { BF66EEB02501AECA007EE018 /* Mapping Models */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A881E7C62D6EF58C00954AD2 /* AltStore11ToAltStore17.xcmappingmodel */, A815AAA02D9108BC00929A9E /* AltStore11ToAltStore17_1.xcmappingmodel */,
A815AA982D90E5E500929A9E /* AltStore17ToAltStore17_1.xcmappingmodel */,
A8C924232D8E73B1009D9953 /* AltStore11ToAltStore17.xcmappingmodel */,
D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */, D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */,
D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */, D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */,
BFBF331A2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel */, BFBF331A2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel */,
@@ -3098,6 +3156,7 @@
A82067842D03DC0600645C0D /* OperatingSystemVersion+Comparable.swift in Sources */, A82067842D03DC0600645C0D /* OperatingSystemVersion+Comparable.swift in Sources */,
D5FB28EE2ADDF89800A1C337 /* KnownSource.swift in Sources */, D5FB28EE2ADDF89800A1C337 /* KnownSource.swift in Sources */,
BF66EED32501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel in Sources */, BF66EED32501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel in Sources */,
A815AA972D90E16400929A9E /* ReleaseTrack17To17_1MigrationPolicy.swift in Sources */,
BF66EEA52501AEC5007EE018 /* Benefit.swift in Sources */, BF66EEA52501AEC5007EE018 /* Benefit.swift in Sources */,
D52B4ABF2AF183F0005991C3 /* WebViewController.swift in Sources */, D52B4ABF2AF183F0005991C3 /* WebViewController.swift in Sources */,
BF66EED22501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel in Sources */, BF66EED22501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel in Sources */,
@@ -3106,17 +3165,26 @@
BF66EECD2501AECA007EE018 /* StoreAppPolicy.swift in Sources */, BF66EECD2501AECA007EE018 /* StoreAppPolicy.swift in Sources */,
BF66EEE82501AED0007EE018 /* UserDefaults+AltStore.swift in Sources */, BF66EEE82501AED0007EE018 /* UserDefaults+AltStore.swift in Sources */,
BF340E9A250AD39500A192CB /* ViewApp.intentdefinition in Sources */, BF340E9A250AD39500A192CB /* ViewApp.intentdefinition in Sources */,
A8C924242D8E73B1009D9953 /* AltStore11ToAltStore17.xcmappingmodel in Sources */,
D552EB062AF453F900A3AB4D /* URL+Normalized.swift in Sources */, D552EB062AF453F900A3AB4D /* URL+Normalized.swift in Sources */,
BFAECC522501B0A400528F27 /* CodableError.swift in Sources */, BFAECC522501B0A400528F27 /* CodableError.swift in Sources */,
A8FD915F2D046F5200322782 /* UserInfoValue.swift in Sources */, A8FD915F2D046F5200322782 /* UserInfoValue.swift in Sources */,
D5F9821D2AB900060045751F /* AppScreenshot.swift in Sources */, D5F9821D2AB900060045751F /* AppScreenshot.swift in Sources */,
BF66EE9E2501AEC1007EE018 /* Fetchable.swift in Sources */, BF66EE9E2501AEC1007EE018 /* Fetchable.swift in Sources */,
BF66EEDF2501AECA007EE018 /* PatreonAccount.swift in Sources */, BF66EEDF2501AECA007EE018 /* PatreonAccount.swift in Sources */,
A815AAA12D9108BC00929A9E /* AltStore11ToAltStore17_1.xcmappingmodel in Sources */,
BFAECC532501B0A400528F27 /* ServerProtocol.swift in Sources */, BFAECC532501B0A400528F27 /* ServerProtocol.swift in Sources */,
A81BF9E52D84CB0C00768940 /* AppPermission17To17_1MigrationPolicy.swift in Sources */,
A81BF9E72D84CB0C00768940 /* Source17To17_1MigrationPolicy.swift in Sources */,
BFAECC572501B0A400528F27 /* ConnectionManager.swift in Sources */, BFAECC572501B0A400528F27 /* ConnectionManager.swift in Sources */,
BF66EE9D2501AEC1007EE018 /* AppProtocol.swift in Sources */, BF66EE9D2501AEC1007EE018 /* AppProtocol.swift in Sources */,
D519AD46292D665B004B12F9 /* Managed.swift in Sources */, D519AD46292D665B004B12F9 /* Managed.swift in Sources */,
D52A2F972ACB40F700BDF8E3 /* Logger+AltStore.swift in Sources */, D52A2F972ACB40F700BDF8E3 /* Logger+AltStore.swift in Sources */,
A815AA952D90D2A100929A9E /* StoreApp17To17_1MigrationPolicy.swift in Sources */,
A815AAA72D9108CB00929A9E /* ReleaseTrack11To17_1MigrationPolicy.swift in Sources */,
A815AAA82D9108CB00929A9E /* AppPermission11To17_1MigrationPolicy.swift in Sources */,
A815AAA92D9108CB00929A9E /* Source11To17_1MigrationPolicy.swift in Sources */,
A815AAAA2D9108CB00929A9E /* StoreApp11To17_1MigrationPolicy.swift in Sources */,
BFC712C42512D5F100AB5EBE /* XPCConnection.swift in Sources */, BFC712C42512D5F100AB5EBE /* XPCConnection.swift in Sources */,
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */, D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */,
BF66EE8C2501AEB2007EE018 /* Keychain.swift in Sources */, BF66EE8C2501AEB2007EE018 /* Keychain.swift in Sources */,
@@ -3179,11 +3247,11 @@
BF66EECE2501AECA007EE018 /* InstalledAppPolicy.swift in Sources */, BF66EECE2501AECA007EE018 /* InstalledAppPolicy.swift in Sources */,
BF1FE359251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift in Sources */, BF1FE359251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift in Sources */,
BF66EEA62501AEC5007EE018 /* PatreonAPI.swift in Sources */, BF66EEA62501AEC5007EE018 /* PatreonAPI.swift in Sources */,
A881E7C72D6EF58C00954AD2 /* AltStore11ToAltStore17.xcmappingmodel in Sources */,
BF66EED02501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel in Sources */, BF66EED02501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel in Sources */,
BF66EEDC2501AECA007EE018 /* MergePolicy.swift in Sources */, BF66EEDC2501AECA007EE018 /* MergePolicy.swift in Sources */,
BF66EEE22501AECA007EE018 /* InstalledExtension.swift in Sources */, BF66EEE22501AECA007EE018 /* InstalledExtension.swift in Sources */,
BF66EED62501AECA007EE018 /* NewsItem.swift in Sources */, BF66EED62501AECA007EE018 /* NewsItem.swift in Sources */,
A815AA992D90E5E500929A9E /* AltStore17ToAltStore17_1.xcmappingmodel in Sources */,
BF66EEA72501AEC5007EE018 /* Campaign.swift in Sources */, BF66EEA72501AEC5007EE018 /* Campaign.swift in Sources */,
D52C8F032AFC56F000CA0BDD /* StoreCategory.swift in Sources */, D52C8F032AFC56F000CA0BDD /* StoreCategory.swift in Sources */,
BF66EE992501AEBC007EE018 /* ALTSourceUserInfoKey.m in Sources */, BF66EE992501AEBC007EE018 /* ALTSourceUserInfoKey.m in Sources */,
@@ -3332,6 +3400,7 @@
BF0C4EBD22A1BD8B009A2DD7 /* AppManager.swift in Sources */, BF0C4EBD22A1BD8B009A2DD7 /* AppManager.swift in Sources */,
BF2901312318F7A800D88A45 /* AppBannerView.swift in Sources */, BF2901312318F7A800D88A45 /* AppBannerView.swift in Sources */,
0EE7FDC42BE8BC7900D1E390 /* ALTLocalizedError.swift in Sources */, 0EE7FDC42BE8BC7900D1E390 /* ALTLocalizedError.swift in Sources */,
A815AA9F2D9104DD00929A9E /* BuildInfo.swift in Sources */,
BFF00D342501BDCF00746320 /* IntentHandler.swift in Sources */, BFF00D342501BDCF00746320 /* IntentHandler.swift in Sources */,
BFDBBD80246CB84F004ED2F3 /* RemoveAppBackupOperation.swift in Sources */, BFDBBD80246CB84F004ED2F3 /* RemoveAppBackupOperation.swift in Sources */,
A8C38C2A2D206AC100E83DBD /* OutputStream.swift in Sources */, A8C38C2A2D206AC100E83DBD /* OutputStream.swift in Sources */,
@@ -4340,6 +4409,7 @@
BF66EEB72501AECA007EE018 /* AltStore.xcdatamodeld */ = { BF66EEB72501AECA007EE018 /* AltStore.xcdatamodeld */ = {
isa = XCVersionGroup; isa = XCVersionGroup;
children = ( children = (
A81BF9E12D84C9E900768940 /* AltStore 17_1.xcdatamodel */,
D51E83802B86926B0092FC61 /* AltStore 17.xcdatamodel */, D51E83802B86926B0092FC61 /* AltStore 17.xcdatamodel */,
D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */, D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */,
D5CA0C4C280E242500469595 /* AltStore 10.xcdatamodel */, D5CA0C4C280E242500469595 /* AltStore 10.xcdatamodel */,
@@ -4353,7 +4423,7 @@
BF66EEBD2501AECA007EE018 /* AltStore 2.xcdatamodel */, BF66EEBD2501AECA007EE018 /* AltStore 2.xcdatamodel */,
BF66EEB92501AECA007EE018 /* AltStore.xcdatamodel */, BF66EEB92501AECA007EE018 /* AltStore.xcdatamodel */,
); );
currentVersion = D51E83802B86926B0092FC61 /* AltStore 17.xcdatamodel */; currentVersion = A81BF9E12D84C9E900768940 /* AltStore 17_1.xcdatamodel */;
path = AltStore.xcdatamodeld; path = AltStore.xcdatamodeld;
sourceTree = "<group>"; sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel; versionGroupType = wrapper.xcdatamodel;

View File

@@ -993,6 +993,7 @@ extension AppManager
case .failure(let error): completionHandler(.failure(error)) case .failure(let error): completionHandler(.failure(error))
case .success(let installedApp): completionHandler(.success(installedApp)) case .success(let installedApp): completionHandler(.success(installedApp))
} }
//UIApplication.shared.open(shortcutURLon, options: [:], completionHandler: nil)
} }
installOperation.addDependency(sendAppOperation) installOperation.addDependency(sendAppOperation)

View File

@@ -360,13 +360,6 @@ extension FetchProvisioningProfilesOperation
} }
} }
class FetchProvisioningProfilesRefreshOperation: FetchProvisioningProfilesOperation, @unchecked Sendable {
override init(context: AppOperationContext)
{
super.init(context: context)
}
}
class FetchProvisioningProfilesInstallOperation: FetchProvisioningProfilesOperation, @unchecked Sendable{ class FetchProvisioningProfilesInstallOperation: FetchProvisioningProfilesOperation, @unchecked Sendable{
override init(context: AppOperationContext) override init(context: AppOperationContext)
{ {
@@ -613,3 +606,14 @@ class FetchProvisioningProfilesInstallOperation: FetchProvisioningProfilesOperat
} }
} }
} }
// <TEST> : users were reporting that refresh (though seemed like it refreshed the app becomes no longer available)
// possibly, this is caused since refesh was not updating appFeatures and AppGroups in the new profile? not sure.
// for now we are reverting by keeping same operation that happens during fetch in install path to see if it fixes issue #893
// class FetchProvisioningProfilesRefreshOperation: FetchProvisioningProfilesOperation, @unchecked Sendable {
class FetchProvisioningProfilesRefreshOperation: FetchProvisioningProfilesInstallOperation, @unchecked Sendable {
override init(context: AppOperationContext)
{
super.init(context: context)
}
}

View File

@@ -11,6 +11,7 @@ import CoreData
import AltStoreCore import AltStoreCore
import Roxas import Roxas
import SemanticVersion
@objc(FetchSourceOperation) @objc(FetchSourceOperation)
final class FetchSourceOperation: ResultOperation<Source> final class FetchSourceOperation: ResultOperation<Source>
@@ -246,9 +247,20 @@ private extension FetchSourceOperation
#endif #endif
} }
if let previousSourceID = self.$source.identifier let incomingSourceID = source.identifier
if let previousSourceID = self.$source.identifier,
incomingSourceID != previousSourceID
{ {
guard source.identifier == previousSourceID else { throw SourceError.changedID(source.identifier, previousID: previousSourceID, source: source) } // if let version = BuildInfo().marketing_version,
// SemanticVersion(version)! <= SemanticVersion("0.6.1")!
// {
// // delete the source, so that incoming will be saved.
// self.source?.managedObjectContext?.delete(self.source!)
// }
// else
// {
throw SourceError.changedID(source.identifier, previousID: self.$source.identifier ?? "nil", source: source)
// }
} }
} }

View File

@@ -13,6 +13,8 @@ import AltSign
import Roxas import Roxas
import minimuxer import minimuxer
let shortcutURLonDelay = URL(string: "shortcuts://run-shortcut?name=TurnOnDataDelay")!
@objc(InstallAppOperation) @objc(InstallAppOperation)
final class InstallAppOperation: ResultOperation<InstalledApp> final class InstallAppOperation: ResultOperation<InstalledApp>
{ {
@@ -204,6 +206,10 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
let alert = UIAlertController(title: "Finish Refresh", message: "Please reopen SideStore after the process is finished.To finish refreshing, SideStore must be moved to the background. To do this, you can either go to the Home Screen manually or by hitting Continue. Please reopen SideStore after doing this.", preferredStyle: .alert) let alert = UIAlertController(title: "Finish Refresh", message: "Please reopen SideStore after the process is finished.To finish refreshing, SideStore must be moved to the background. To do this, you can either go to the Home Screen manually or by hitting Continue. Please reopen SideStore after doing this.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in
print("Going home") print("Going home")
// Cell Shortcut
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
print("Cell OFF Shortcut finished execution.")}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
})) }))
@@ -220,6 +226,8 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
} }
} }
} }
// Cell Shortcut
UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in print("Cell OFF Shortcut finished execution.")}
UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
} }
} }

View File

@@ -212,7 +212,6 @@ private extension PatchAppOperation
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion) throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion)
#else #else
let spotlightPath = "Applications/Spotlight.app/Spotlight" let spotlightPath = "Applications/Spotlight.app/Spotlight"
let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath) let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath)

View File

@@ -27,12 +27,10 @@ final class SendAppOperation: ResultOperation<()>
self.progress.totalUnitCount = 1 self.progress.totalUnitCount = 1
} }
override func main() override func main() {
{
super.main() super.main()
if let error = self.context.error if let error = self.context.error {
{
return self.finish(.failure(error)) return self.finish(.failure(error))
} }
@@ -40,16 +38,31 @@ final class SendAppOperation: ResultOperation<()>
return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil"))) return self.finish(.failure(OperationError.invalidParameters("SendAppOperation.main: self.resignedApp is nil")))
} }
// self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa. let shortcutURLoff = URL(string: "shortcuts://run-shortcut?name=TurnOffData")!
let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL, storeApp: nil) let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL, storeApp: nil)
let fileURL = InstalledApp.refreshedIPAURL(for: app) let fileURL = InstalledApp.refreshedIPAURL(for: app)
print("AFC App `fileURL`: \(fileURL.absoluteString)") print("AFC App `fileURL`: \(fileURL.absoluteString)")
if let data = NSData(contentsOf: fileURL) { // Wait for Shortcut to Finish Before Proceeding
UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in
print("Shortcut finished execution. Proceeding with file transfer.")
DispatchQueue.global().async {
self.processFile(at: fileURL, for: app.bundleIdentifier)
}
}
}
private func processFile(at fileURL: URL, for bundleIdentifier: String) {
guard let data = NSData(contentsOf: fileURL) else {
print("IPA doesn't exist????")
return self.finish(.failure(OperationError(.appNotFound(name: bundleIdentifier))))
}
do { do {
let bytes = Data(data).toRustByteSlice() let bytes = Data(data).toRustByteSlice()
try yeet_app_afc(app.bundleIdentifier, bytes.forRust()) try yeet_app_afc(bundleIdentifier, bytes.forRust())
self.progress.completedUnitCount += 1 self.progress.completedUnitCount += 1
self.finish(.success(())) self.finish(.success(()))
} catch { } catch {
@@ -57,9 +70,5 @@ final class SendAppOperation: ResultOperation<()>
self.progress.completedUnitCount += 1 self.progress.completedUnitCount += 1
self.finish(.success(())) self.finish(.success(()))
} }
} else {
print("IPA doesn't exist????")
self.finish(.failure(OperationError(.appNotFound(name: resignedApp.name))))
}
} }
} }

View File

@@ -263,50 +263,6 @@ final class SettingsViewController: UITableViewController
} }
private class BuildInfo{
private static let MARKETING_VERSION_TAG = "CFBundleShortVersionString"
private static let CURRENT_PROJECT_VERSION_TAG = kCFBundleVersionKey as String
private static let XCODE_VERSION_TAG = "DTXcode"
private static let XCODE_REVISION_TAG = "DTXcodeBuild"
let bundle: Bundle
public init(){
bundle = Bundle.main
}
enum BundleError: Swift.Error {
case invalidURL
}
public init(url: URL) throws {
guard let bundle = Bundle(url: url) else {
throw BundleError.invalidURL
}
self.bundle = bundle
}
public lazy var project_version: String? = {
let version = bundle.object(forInfoDictionaryKey: Self.CURRENT_PROJECT_VERSION_TAG) as? String
return version
}()
public lazy var marketing_version: String? = {
let version = bundle.object(forInfoDictionaryKey: Self.MARKETING_VERSION_TAG) as? String
return version
}()
public lazy var xcode: String? = {
let xcode = bundle.object(forInfoDictionaryKey: Self.XCODE_VERSION_TAG) as? String
return xcode
}()
public lazy var xcode_revision: String? = {
let revision = bundle.object(forInfoDictionaryKey: Self.XCODE_REVISION_TAG) as? String
return revision
}()
}
private extension SettingsViewController private extension SettingsViewController
{ {
@@ -993,7 +949,7 @@ extension SettingsViewController
// Option 2: Discord // Option 2: Discord
alertController.addAction(UIAlertAction(title: "Discord", style: .default) { _ in alertController.addAction(UIAlertAction(title: "Discord", style: .default) { _ in
if let discordURL = URL(string: "https://discord.gg/sidestore") { if let discordURL = URL(string: "https://discord.gg/sidestore-949183273383395328") {
let safariViewController = SFSafariViewController(url: discordURL) let safariViewController = SFSafariViewController(url: discordURL)
safariViewController.preferredControlTintColor = .altPrimary safariViewController.preferredControlTintColor = .altPrimary
self.present(safariViewController, animated: true, completion: nil) self.present(safariViewController, animated: true, completion: nil)

View File

@@ -514,27 +514,27 @@ extension SourcesViewController: NSFetchedResultsControllerDelegate
let context = DatabaseManager.shared.persistentContainer.newBackgroundContext() let context = DatabaseManager.shared.persistentContainer.newBackgroundContext()
context.performAndWait { context.performAndWait {
_ = Source.make(name: "OatmealDome's AltStore Source", _ = Source.make(name: "OatmealDome's AltStore Source",
identifier: "me.oatmealdome.altstore", groupID: "me.oatmealdome.altstore",
sourceURL: URL(string: "https://altstore.oatmealdome.me")!, sourceURL: URL(string: "https://altstore.oatmealdome.me")!,
context: context) context: context)
_ = Source.make(name: "UTM Repository", _ = Source.make(name: "UTM Repository",
identifier: "com.utmapp.repos.UTM", groupID: "com.utmapp.repos.UTM",
sourceURL: URL(string: "https://alt.getutm.app")!, sourceURL: URL(string: "https://alt.getutm.app")!,
context: context) context: context)
_ = Source.make(name: "Flyinghead", _ = Source.make(name: "Flyinghead",
identifier: "com.flyinghead.source", groupID: "com.flyinghead.source",
sourceURL: URL(string: "https://flyinghead.github.io/flycast-builds/altstore.json")!, sourceURL: URL(string: "https://flyinghead.github.io/flycast-builds/altstore.json")!,
context: context) context: context)
_ = Source.make(name: "Provenance", _ = Source.make(name: "Provenance",
identifier: "org.provenance-emu.AltStore", groupID: "org.provenance-emu.AltStore",
sourceURL: URL(string: "https://provenance-emu.com/apps.json")!, sourceURL: URL(string: "https://provenance-emu.com/apps.json")!,
context: context) context: context)
_ = Source.make(name: "PojavLauncher Repository", _ = Source.make(name: "PojavLauncher Repository",
identifier: "dev.crystall1ne.repos.PojavLauncher", groupID: "dev.crystall1ne.repos.PojavLauncher",
sourceURL: URL(string: "http://alt.crystall1ne.dev")!, sourceURL: URL(string: "http://alt.crystall1ne.dev")!,
context: context) context: context)

View File

@@ -3,6 +3,6 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>_XCCurrentVersionName</key> <key>_XCCurrentVersionName</key>
<string>AltStore 17.xcdatamodel</string> <string>AltStore 17_1.xcdatamodel</string>
</dict> </dict>
</plist> </plist>

View File

@@ -0,0 +1,315 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23605" systemVersion="24D70" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="v17.1">
<entity name="Account" representedClassName="Account" syncable="YES">
<attribute name="appleID" attributeType="String"/>
<attribute name="firstName" attributeType="String"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="isActiveAccount" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="lastName" attributeType="String"/>
<relationship name="teams" toMany="YES" deletionRule="Cascade" destinationEntity="Team" inverseName="account" inverseEntity="Team"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="AppID" representedClassName="AppID" syncable="YES">
<attribute name="bundleIdentifier" attributeType="String"/>
<attribute name="expirationDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="features" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="name" attributeType="String"/>
<relationship name="team" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Team" inverseName="appIDs" inverseEntity="Team"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="AppPermission" representedClassName="AppPermission" syncable="YES">
<attribute name="appBundleID" optional="YES" attributeType="String"/>
<attribute name="permission" optional="YES" attributeType="String"/>
<attribute name="sourceID" optional="YES" attributeType="String"/>
<attribute name="type" attributeType="String"/>
<attribute name="usageDescription" attributeType="String"/>
<relationship name="app" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="permissions" inverseEntity="StoreApp"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="sourceID"/>
<constraint value="appBundleID"/>
<constraint value="type"/>
<constraint value="permission"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="AppScreenshot" representedClassName="AppScreenshot" syncable="YES">
<attribute name="appBundleID" optional="YES" attributeType="String"/>
<attribute name="deviceType" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="height" optional="YES" attributeType="Integer 16" usesScalarValueType="NO"/>
<attribute name="imageURL" attributeType="URI"/>
<attribute name="sourceID" optional="YES" attributeType="String"/>
<attribute name="width" optional="YES" attributeType="Integer 16" usesScalarValueType="NO"/>
<relationship name="app" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="screenshots" inverseEntity="StoreApp"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="sourceID"/>
<constraint value="appBundleID"/>
<constraint value="imageURL"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="AppVersion" representedClassName="AppVersion" syncable="YES">
<attribute name="appBundleID" optional="YES" attributeType="String"/>
<attribute name="buildVersion" optional="YES" attributeType="String"/>
<attribute name="channel" optional="YES" attributeType="String"/>
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="downloadURL" attributeType="URI"/>
<attribute name="localizedDescription" optional="YES" attributeType="String"/>
<attribute name="maxOSVersion" optional="YES" attributeType="String"/>
<attribute name="minOSVersion" optional="YES" attributeType="String"/>
<attribute name="sha256" optional="YES" attributeType="String"/>
<attribute name="size" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="sourceID" optional="YES" attributeType="String"/>
<attribute name="version" attributeType="String"/>
<relationship name="app" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="versions" inverseEntity="StoreApp"/>
<relationship name="latestVersionApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="latestVersion" inverseEntity="StoreApp"/>
<relationship name="releaseTrack" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ReleaseTrack" inverseName="releases" inverseEntity="ReleaseTrack"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="sourceID"/>
<constraint value="appBundleID"/>
<constraint value="version"/>
<constraint value="buildVersion"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="InstalledApp" representedClassName="InstalledApp" syncable="YES">
<attribute name="buildVersion" optional="YES" attributeType="String"/>
<attribute name="bundleIdentifier" attributeType="String"/>
<attribute name="certificateSerialNumber" optional="YES" attributeType="String"/>
<attribute name="expirationDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="hasAlternateIcon" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="hasUpdate" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="installedDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="isActive" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="isRefreshing" transient="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String"/>
<attribute name="needsResign" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="refreshedDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="resignedBundleIdentifier" attributeType="String"/>
<attribute name="storeBuildVersion" optional="YES" attributeType="String"/>
<attribute name="version" attributeType="String"/>
<relationship name="appExtensions" toMany="YES" deletionRule="Cascade" destinationEntity="InstalledExtension" inverseName="parentApp" inverseEntity="InstalledExtension"/>
<relationship name="loggedErrors" toMany="YES" deletionRule="Nullify" destinationEntity="LoggedError" inverseName="installedApp" inverseEntity="LoggedError"/>
<relationship name="storeApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="installedApp" inverseEntity="StoreApp"/>
<relationship name="team" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Team" inverseName="installedApps" inverseEntity="Team"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="bundleIdentifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="InstalledExtension" representedClassName="InstalledExtension" syncable="YES">
<attribute name="bundleIdentifier" attributeType="String"/>
<attribute name="expirationDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="installedDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="name" attributeType="String"/>
<attribute name="refreshedDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="resignedBundleIdentifier" attributeType="String"/>
<attribute name="version" attributeType="String"/>
<relationship name="parentApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="InstalledApp" inverseName="appExtensions" inverseEntity="InstalledApp"/>
</entity>
<entity name="LoggedError" representedClassName="LoggedError" syncable="YES">
<attribute name="appBundleID" attributeType="String"/>
<attribute name="appName" attributeType="String"/>
<attribute name="code" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="operation" optional="YES" attributeType="String"/>
<attribute name="userInfo" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<relationship name="installedApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="InstalledApp" inverseName="loggedErrors" inverseEntity="InstalledApp"/>
<relationship name="storeApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="loggedErrors" inverseEntity="StoreApp"/>
</entity>
<entity name="NewsItem" representedClassName="NewsItem" syncable="YES">
<attribute name="appID" optional="YES" attributeType="String"/>
<attribute name="caption" attributeType="String"/>
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="externalURL" optional="YES" attributeType="URI"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="imageURL" optional="YES" attributeType="URI"/>
<attribute name="isSilent" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="sortIndex" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="sourceIdentifier" optional="YES" attributeType="String"/>
<attribute name="tintColor" optional="YES" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="title" attributeType="String"/>
<relationship name="source" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Source" inverseName="newsItems" inverseEntity="Source"/>
<relationship name="storeApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="newsItems" inverseEntity="StoreApp"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
<constraint value="sourceIdentifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="PatreonAccount" representedClassName="PatreonAccount" syncable="YES">
<attribute name="firstName" optional="YES" attributeType="String"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="isPatron" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String"/>
<relationship name="pledges" toMany="YES" deletionRule="Cascade" destinationEntity="Pledge" inverseName="account" inverseEntity="Pledge"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="Patron" representedClassName="ManagedPatron" syncable="YES">
<attribute name="identifier" attributeType="String"/>
<attribute name="name" attributeType="String"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="Pledge" representedClassName="Pledge" syncable="YES">
<attribute name="amount" attributeType="Decimal" defaultValueString="0"/>
<attribute name="campaignURL" attributeType="URI"/>
<attribute name="identifier" attributeType="String"/>
<relationship name="account" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PatreonAccount" inverseName="pledges" inverseEntity="PatreonAccount"/>
<relationship name="rewards" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="PledgeReward" inverseName="pledge" inverseEntity="PledgeReward"/>
<relationship name="tiers" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="PledgeTier" inverseName="pledge" inverseEntity="PledgeTier"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="PledgeReward" representedClassName="PledgeReward" syncable="YES">
<attribute name="identifier" attributeType="String"/>
<attribute name="name" attributeType="String"/>
<relationship name="pledge" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Pledge" inverseName="rewards" inverseEntity="Pledge"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="PledgeTier" representedClassName="PledgeTier" syncable="YES">
<attribute name="amount" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="name" optional="YES" attributeType="String"/>
<relationship name="pledge" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Pledge" inverseName="tiers" inverseEntity="Pledge"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="RefreshAttempt" representedClassName="RefreshAttempt" syncable="YES">
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="errorDescription" optional="YES" attributeType="String"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="isSuccess" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="ReleaseTrack" representedClassName="ReleaseTrack" syncable="YES">
<attribute name="appBundleID" optional="YES" attributeType="String"/>
<attribute name="sourceID" optional="YES" attributeType="String"/>
<attribute name="track" attributeType="String"/>
<relationship name="releases" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="AppVersion" inverseName="releaseTrack" inverseEntity="AppVersion"/>
<relationship name="storeApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreApp" inverseName="releaseTracks" inverseEntity="StoreApp"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="sourceID"/>
<constraint value="appBundleID"/>
<constraint value="track"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="Source" representedClassName="Source" syncable="YES">
<attribute name="error" optional="YES" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="featuredSortID" optional="YES" attributeType="String"/>
<attribute name="groupID" optional="YES" attributeType="String"/>
<attribute name="hasFeaturedApps" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="headerImageURL" optional="YES" attributeType="URI"/>
<attribute name="iconURL" optional="YES" attributeType="URI"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="localizedDescription" optional="YES" attributeType="String"/>
<attribute name="name" attributeType="String"/>
<attribute name="patreonURL" optional="YES" attributeType="URI"/>
<attribute name="sourceURL" attributeType="URI"/>
<attribute name="subtitle" optional="YES" attributeType="String"/>
<attribute name="tintColor" optional="YES" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="version" attributeType="Integer 64" defaultValueString="1" usesScalarValueType="YES"/>
<attribute name="websiteURL" optional="YES" attributeType="URI"/>
<relationship name="apps" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="StoreApp" inverseName="source" inverseEntity="StoreApp"/>
<relationship name="featuredApps" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="StoreApp" inverseName="featuringSource" inverseEntity="StoreApp"/>
<relationship name="newsItems" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="NewsItem" inverseName="source" inverseEntity="NewsItem"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="StoreApp" representedClassName="StoreApp" syncable="YES">
<attribute name="bundleIdentifier" attributeType="String"/>
<attribute name="category" optional="YES" attributeType="String"/>
<attribute name="developerName" attributeType="String"/>
<attribute name="downloadURL" optional="YES" attributeType="URI"/>
<attribute name="featuredSortID" optional="YES" attributeType="String"/>
<attribute name="iconURL" attributeType="URI"/>
<attribute name="isHiddenWithoutPledge" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="isPledged" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="isPledgeRequired" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="localizedDescription" attributeType="String"/>
<attribute name="marketplaceID" optional="YES" attributeType="String"/>
<attribute name="name" attributeType="String"/>
<attribute name="pledgeAmount" optional="YES" attributeType="Decimal"/>
<attribute name="pledgeCurrency" optional="YES" attributeType="String"/>
<attribute name="prefersCustomPledge" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="screenshotURLs" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="size" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="sortIndex" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="sourceIdentifier" optional="YES" attributeType="String"/>
<attribute name="subtitle" optional="YES" attributeType="String"/>
<attribute name="tintColor" optional="YES" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="version" optional="YES" attributeType="String"/>
<attribute name="versionDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="versionDescription" optional="YES" attributeType="String"/>
<relationship name="featuringSource" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Source" inverseName="featuredApps" inverseEntity="Source"/>
<relationship name="installedApp" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="InstalledApp" inverseName="storeApp" inverseEntity="InstalledApp"/>
<relationship name="latestVersion" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AppVersion" inverseName="latestVersionApp" inverseEntity="AppVersion"/>
<relationship name="loggedErrors" toMany="YES" deletionRule="Nullify" destinationEntity="LoggedError" inverseName="storeApp" inverseEntity="LoggedError"/>
<relationship name="newsItems" toMany="YES" deletionRule="Nullify" destinationEntity="NewsItem" inverseName="storeApp" inverseEntity="NewsItem"/>
<relationship name="permissions" toMany="YES" deletionRule="Cascade" destinationEntity="AppPermission" inverseName="app" inverseEntity="AppPermission"/>
<relationship name="releaseTracks" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="ReleaseTrack" inverseName="storeApp" inverseEntity="ReleaseTrack"/>
<relationship name="screenshots" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="AppScreenshot" inverseName="app" inverseEntity="AppScreenshot"/>
<relationship name="source" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Source" inverseName="apps" inverseEntity="Source"/>
<relationship name="versions" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="AppVersion" inverseName="app" inverseEntity="AppVersion"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="sourceIdentifier"/>
<constraint value="bundleIdentifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="Team" representedClassName="Team" syncable="YES">
<attribute name="identifier" attributeType="String"/>
<attribute name="isActiveTeam" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String"/>
<attribute name="type" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="account" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Account" inverseName="teams" inverseEntity="Account"/>
<relationship name="appIDs" toMany="YES" deletionRule="Cascade" destinationEntity="AppID" inverseName="team" inverseEntity="AppID"/>
<relationship name="installedApps" toMany="YES" deletionRule="Nullify" destinationEntity="InstalledApp" inverseName="team" inverseEntity="InstalledApp"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="identifier"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
</model>

View File

@@ -33,7 +33,7 @@ public class AppPermission: BaseEntity
default: return UnknownAppPermission(rawValue: self._permission) default: return UnknownAppPermission(rawValue: self._permission)
} }
} }
@NSManaged @objc(permission) private var _permission: String @NSManaged @objc(permission) private(set) public var _permission: String
// Set by StoreApp. // Set by StoreApp.
@NSManaged public var appBundleID: String @NSManaged public var appBundleID: String

View File

@@ -141,7 +141,7 @@ public class InstalledApp: BaseEntity, InstalledAppProtocol
let latestVer = SemanticVersion("\(latestSemVer!.major).\(latestSemVer!.minor).\(latestSemVer!.patch)") let latestVer = SemanticVersion("\(latestSemVer!.major).\(latestSemVer!.minor).\(latestSemVer!.patch)")
// Compare by major.minor.patch // Compare by major.minor.patch
if latestVer! > latestVer! { if latestVer! > currentVer! {
return true return true
} }

View File

@@ -213,6 +213,7 @@ extension MergePolicy{
} }
default: default:
// break
// Unknown context-level conflict. // Unknown context-level conflict.
// assertionFailure("MergePolicy is only intended to work with database-level conflicts.") // assertionFailure("MergePolicy is only intended to work with database-level conflicts.")
assertionFailure("Context Conflict Detected: is there ambigious data in your incoming sources?\nConflict:\(conflict)") assertionFailure("Context Conflict Detected: is there ambigious data in your incoming sources?\nConflict:\(conflict)")

View File

@@ -505,13 +505,14 @@ cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxESLAALAAwAGQA1ADYANwBjAGQAZQBm
<relationship name="relationshipmappings" type="0/0" destination="XDDEVRELATIONSHIPMAPPING" idrefs="z142 z119 z223 z116 z229 z139 z236 z136 z214 z216"></relationship> <relationship name="relationshipmappings" type="0/0" destination="XDDEVRELATIONSHIPMAPPING" idrefs="z142 z119 z223 z116 z229 z139 z236 z136 z214 z216"></relationship>
</object> </object>
<object type="XDDEVENTITYMAPPING" id="z198"> <object type="XDDEVENTITYMAPPING" id="z198">
<attribute name="migrationpolicyclassname" type="string"></attribute>
<attribute name="sourcename" type="string">AppPermission</attribute> <attribute name="sourcename" type="string">AppPermission</attribute>
<attribute name="mappingtypename" type="string">Undefined</attribute> <attribute name="mappingtypename" type="string">Undefined</attribute>
<attribute name="mappingnumber" type="int16">17</attribute> <attribute name="mappingnumber" type="int16">17</attribute>
<attribute name="destinationname" type="string">AppPermission</attribute> <attribute name="destinationname" type="string">AppPermission</attribute>
<attribute name="autogenerateexpression" type="bool">1</attribute> <attribute name="autogenerateexpression" type="bool">1</attribute>
<relationship name="mappingmodel" type="1/1" destination="XDDEVMAPPINGMODEL" idrefs="z192"></relationship> <relationship name="mappingmodel" type="1/1" destination="XDDEVMAPPINGMODEL" idrefs="z192"></relationship>
<relationship name="attributemappings" type="0/0" destination="XDDEVATTRIBUTEMAPPING" idrefs="z213 z240 z191 z123 z287"></relationship> <relationship name="attributemappings" type="0/0" destination="XDDEVATTRIBUTEMAPPING" idrefs="z123 z213 z287 z240 z191"></relationship>
<relationship name="relationshipmappings" type="0/0" destination="XDDEVRELATIONSHIPMAPPING" idrefs="z288"></relationship> <relationship name="relationshipmappings" type="0/0" destination="XDDEVRELATIONSHIPMAPPING" idrefs="z288"></relationship>
</object> </object>
<object type="XDDEVENTITYMAPPING" id="z199"> <object type="XDDEVENTITYMAPPING" id="z199">

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
// //
// SourceMigrationPolicy.swift // Source11To17MigrationPolicy.swift
// AltStoreCore // AltStoreCore
// //
// Created by Riley Testut on 10/19/23. // Created by Riley Testut on 10/19/23.

View File

@@ -1,5 +1,5 @@
// //
// StoreAppMigration11To17Policy.swift // StoreApp11To17MigrationPolicy.swift
// AltStore // AltStore
// //
// Created by Magesh K on 25/02/25. // Created by Magesh K on 25/02/25.
@@ -108,7 +108,7 @@ class StoreApp11To17MigrationPolicy: NSEntityMigrationPolicy {
// Create a new ReleaseTrack entity // Create a new ReleaseTrack entity
let context = dInstance.managedObjectContext! let context = dInstance.managedObjectContext!
let releaseTrack = NSEntityDescription.insertNewObject(forEntityName: ReleaseTrack.entity().name!, into: context) let releaseTrack = NSEntityDescription.insertNewObject(forEntityName: ReleaseTrack.entity().name ?? ReleaseTrack.description(), into: context)
releaseTrack.setValue(defaultChannel, forKey: #keyPath(ReleaseTrack._track)) releaseTrack.setValue(defaultChannel, forKey: #keyPath(ReleaseTrack._track))
// Connect the releaseTrack to the destination StoreApp // Connect the releaseTrack to the destination StoreApp
@@ -116,7 +116,7 @@ class StoreApp11To17MigrationPolicy: NSEntityMigrationPolicy {
// Find the mapping name for AppVersion (make sure this exactly matches your mapping model) // Find the mapping name for AppVersion (make sure this exactly matches your mapping model)
let appVersionMappingName = findEntityMappingName(for: AppVersion.entity().name!, in: manager) let appVersionMappingName = findEntityMappingName(for: AppVersion.entity().name ?? AppVersion.description(), in: manager)
// Create a mutable ordered set for the destination AppVersion objects // Create a mutable ordered set for the destination AppVersion objects
let destinationVersionsSet = NSMutableOrderedSet() let destinationVersionsSet = NSMutableOrderedSet()
@@ -145,5 +145,5 @@ class StoreApp11To17MigrationPolicy: NSEntityMigrationPolicy {
// dInstance.setValue(NSOrderedSet(), forKey: #keyPath(StoreApp._versions)) // dInstance.setValue(NSOrderedSet(), forKey: #keyPath(StoreApp._versions))
dInstance.setValue(nil, forKey: #keyPath(StoreApp._versions)) dInstance.setValue(nil, forKey: #keyPath(StoreApp._versions))
} }
} }

View File

@@ -0,0 +1,28 @@
//
// AppPermission17to17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
@objc(AppPermission11To17_1MigrationPolicy)
class AppPermission11To17_1MigrationPolicy: AppPermission17To17_1MigrationPolicy {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
// Let the default implementation create the basic destination AppPermission
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
}
override func createRelationships(
forDestination dInstance: NSManagedObject,
in mapping: NSEntityMapping,
manager: NSMigrationManager
) throws {
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
}
}

View File

@@ -0,0 +1,26 @@
//
// ReleaseTrack11To17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
@objc(ReleaseTrack11To17_1MigrationPolicy)
class ReleaseTrack11To17_1MigrationPolicy: ReleaseTrack17To17_1MigrationPolicy {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
}
override func createRelationships(
forDestination dInstance: NSManagedObject,
in mapping: NSEntityMapping,
manager: NSMigrationManager
) throws {
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
}
}

View File

@@ -0,0 +1,23 @@
//
// Source11To17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
@objc(Source11To17_1MigrationPolicy)
class Source11To17_1MigrationPolicy: Source17To17_1MigrationPolicy
{
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
// Let the default implementation create the basic destination AppPermission
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
}
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws
{
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
}
}

View File

@@ -0,0 +1,62 @@
//
// StoreApp11To17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
fileprivate extension NSManagedObject
{
var storeAppReleaseTracks: NSOrderedSet? {
let tracks = self.value(forKey: #keyPath(StoreApp._releaseTracks)) as? NSOrderedSet
return tracks
}
}
@objc(StoreApp11To17_1MigrationPolicy)
class StoreApp11To17_1MigrationPolicy: StoreApp11To17MigrationPolicy
{
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
}
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws
{
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
let appBundleID = dInstance.value(forKey: #keyPath(StoreApp.bundleIdentifier))
let sourceID = dInstance.value(forKey: #keyPath(StoreApp.sourceIdentifier))
for case let track as NSManagedObject in dInstance.storeAppReleaseTracks ?? []
{
track.setValue(appBundleID, forKey: #keyPath(ReleaseTrack._appBundleID))
track.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
guard let releases = track.value(forKey: #keyPath(ReleaseTrack._releases)) as? NSOrderedSet else {
continue
}
for case let version as NSManagedObject in releases {
version.setValue(appBundleID, forKey: #keyPath(AppVersion.appBundleID))
version.setValue(sourceID, forKey: #keyPath(AppVersion.sourceID))
}
}
if let permissions = dInstance.value(forKey: #keyPath(StoreApp._permissions)) as? NSSet {
for case let permission as NSManagedObject in permissions {
permission.setValue(appBundleID, forKey: #keyPath(AppPermission.appBundleID))
permission.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
}
}
if let screenshots = dInstance.value(forKey: #keyPath(StoreApp._screenshots)) as? NSOrderedSet {
for case let screenshot as NSManagedObject in screenshots {
screenshot.setValue(appBundleID, forKey: #keyPath(AppScreenshot.appBundleID))
screenshot.setValue(sourceID, forKey: #keyPath(AppScreenshot.sourceID))
}
}
}
}

View File

@@ -0,0 +1,100 @@
//
// AppPermission17to17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
@objc(AppPermission17To17_1MigrationPolicy)
class AppPermission17To17_1MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
// Let the default implementation create the basic destination AppPermission
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
// Get the destination AppPermission instance that was created
guard let destinationPermission = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else {
print("Failed to locate destination AppPermission instance")
return
}
// Extract the type value from source
if let type = sInstance.value(forKey: #keyPath(AppPermission.type)) as? String {
// this is for backwards compatibility <0.5.10
// if older type was a valid permission, then consider it as "privacy" in the newer "type".
if let permission = self.derivePermissionFromType(type) {
destinationPermission.setValue(permission, forKey: #keyPath(AppPermission._permission))
destinationPermission.setValue("privacy", forKey: #keyPath(AppPermission.type))
}
}
// set initial values copied from source as-is
// (will be updated by StoreApp and Source migration policy in its createRelationship() method)
if let storeApp = sInstance.value(forKey: #keyPath(AppPermission.app)) as? NSManagedObject{
if let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String{
destinationPermission.setValue(appBundle, forKey: #keyPath(AppPermission.appBundleID))
}
if let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String {
destinationPermission.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
}
}
}
override func createRelationships(
forDestination dInstance: NSManagedObject,
in mapping: NSEntityMapping,
manager: NSMigrationManager
) throws {
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
// Retrieve the source storeApp from the source appPermission
guard let storeApp = dInstance.value(forKey: #keyPath(AppPermission.app)) as? NSManagedObject else {
print("Destination \(AppPermission.description()) has no storeApp")
return
}
// set initial values copied from source as-is to satisfy unique constraints
// (will be updated by StoreApp and Source migration policy in its createRelationship() method)
if let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String{
dInstance.setValue(appBundle, forKey: #keyPath(AppPermission.appBundleID))
}
if let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String {
dInstance.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
}
}
// Helper method to derive permission string from type
private func derivePermissionFromType(_ type: String) -> String? {
// Based on the code in the documents, we need to map the ALTAppPermissionType to permission strings
switch type {
case "photos": return "NSPhotosUsageDescription"
case "camera": return "NSCameraUsageDescription"
case "location": return "NSLocationUsageDescription"
case "contacts": return "NSContactsUsageDescription"
case "reminders": return "NSRemindersUsageDescription"
case "music": return "NSAppleMusicUsageDescription"
case "microphone": return "NSMicrophoneUsageDescription"
case "speech-recognition": return "NSSpeechRecognitionUsageDescription"
case "background-audio": return "NSBackgroundAudioUsageDescription"
case "background-fetch": return "NSBackgroundFetchUsageDescription"
case "bluetooth": return "NSBluetoothUsageDescription"
case "network": return "NSNetworkUsageDescription"
case "calendars": return "NSCalendarsUsageDescription"
case "touchID": return "NSTouchIDUsageDescription"
case "faceID": return "NSFaceIDUsageDescription"
case "siri": return "NSSiriUsageDescription"
case "motion": return "NSMotionUsageDescription"
default: return nil // Default fallback
}
}
}

View File

@@ -0,0 +1,57 @@
//
// ReleaseTrack17To17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
@objc(ReleaseTrack17To17_1MigrationPolicy)
class ReleaseTrack17To17_1MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
}
override func createRelationships(
forDestination dInstance: NSManagedObject,
in mapping: NSEntityMapping,
manager: NSMigrationManager
) throws {
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
// Retrieve the source storeApp from the source ReleaseTrack
guard let storeApp = dInstance.value(forKey: #keyPath(ReleaseTrack.storeApp)) as? NSManagedObject else {
print("Destination \(ReleaseTrack.description()) has no storeApp")
return
}
// set initial values copied from source as-is to satisfy unique constraints
// (will be updated by StoreApp and Source migration policy in its createRelationship() method)
let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String
let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String
if let appBundle {
dInstance.setValue(appBundle, forKey: #keyPath(ReleaseTrack._appBundleID))
}
if let sourceID {
dInstance.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
}
if let releases = dInstance.value(forKey: #keyPath(ReleaseTrack._releases)) as? NSOrderedSet {
for case let version as NSManagedObject in releases {
if let appBundle {
version.setValue(appBundle, forKey: #keyPath(AppVersion.appBundleID))
}
if let sourceID {
version.setValue(sourceID, forKey: #keyPath(AppVersion.sourceID))
}
}
}
}
}

View File

@@ -0,0 +1,191 @@
//
// Source17To17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
fileprivate extension NSManagedObject
{
var sourceSourceURL: URL? {
let sourceURL = self.value(forKey: #keyPath(Source.sourceURL)) as? URL
return sourceURL
}
var sourceSourceId: String? {
let sourceId = self.value(forKey: #keyPath(Source.identifier)) as? String
return sourceId
}
var sourceApps: NSOrderedSet? {
let apps = self.value(forKey: #keyPath(Source._apps)) as? NSOrderedSet
return apps
}
var sourceNewsItems: NSOrderedSet? {
let newsItems = self.value(forKey: #keyPath(Source._newsItems)) as? NSOrderedSet
return newsItems
}
}
fileprivate extension NSManagedObject
{
func setSourceId(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(Source.identifier))
}
func setGroupId(_ groupID: String)
{
self.setValue(groupID, forKey: #keyPath(Source.groupID))
}
func setSourceSourceUrl(_ sourceURL: URL)
{
self.setValue(sourceURL, forKey: #keyPath(Source.sourceURL))
}
func setSourceSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(Source.identifier))
}
func setStoreAppSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(StoreApp.sourceIdentifier))
}
func setNewsItemSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(NewsItem.sourceIdentifier))
}
func setAppVersionSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(AppVersion.sourceID))
}
func setAppPermissionSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
}
func setAppScreenshotSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(AppScreenshot.sourceID))
}
func setReleaseTracksSourceID(_ sourceID: String)
{
self.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
}
}
fileprivate extension NSManagedObject
{
var storeAppVersions: NSOrderedSet? {
let versions = self.value(forKey: #keyPath(StoreApp._versions)) as? NSOrderedSet
return versions
}
var storeAppPermissions: NSSet? {
let permissions = self.value(forKey: #keyPath(StoreApp._permissions)) as? NSSet
return permissions
}
var storeAppScreenshots: NSOrderedSet? {
let screenshots = self.value(forKey: #keyPath(StoreApp._screenshots)) as? NSOrderedSet
return screenshots
}
var storeAppReleaseTracks: NSOrderedSet? {
let tracks = self.value(forKey: #keyPath(StoreApp._releaseTracks)) as? NSOrderedSet
return tracks
}
}
@objc(Source17To17_1MigrationPolicy)
class Source17To17_1MigrationPolicy: NSEntityMigrationPolicy
{
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
// Let the default implementation create the basic destination AppPermission
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
// Get the destination Source instance that was created
guard let dInstance = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else {
print("Failed to locate destination Source instance")
return
}
// update new fields with initial values
if let sourceID = sInstance.value(forKey: #keyPath(Source.identifier)) as? String {
dInstance.setValue(sourceID, forKey: #keyPath(Source.groupID))
}
guard var sourceURL = dInstance.sourceSourceURL else {
return
}
// sidestore official source has been moved to sidestore.io/apps-v2.json
// if we don't switch, users will end up with 2 offical sources
let normalizedSourceURL = try? sourceURL.normalized()
if normalizedSourceURL == "apps.sidestore.io" // if using old source url (<0.5.9)
{
sourceURL = Source.altStoreSourceURL // switch to latest
dInstance.setSourceSourceUrl(sourceURL) // and use it for current
}
var sourceID = try Source.sourceID(from: sourceURL)
dInstance.setSourceId(sourceID)
// for older versions migrating to current (their sourceID is their groupID)
dInstance.setGroupId(sourceID)
if sourceID == "apps.sidestore.io" {
sourceID = Source.altStoreIdentifier
dInstance.setSourceId(sourceID)
}
}
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws
{
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
guard let sourceID = dInstance.sourceSourceId else { return }
for case let newsItem as NSManagedObject in dInstance.sourceNewsItems ?? []
{
newsItem.setNewsItemSourceID(sourceID)
}
for case let app as NSManagedObject in dInstance.sourceApps ?? []
{
app.setStoreAppSourceID(sourceID)
for case let screenshot as NSManagedObject in app.storeAppScreenshots ?? []
{
screenshot.setAppScreenshotSourceID(sourceID)
}
for case let track as NSManagedObject in app.storeAppReleaseTracks ?? []
{
// print("Source_17_1MigrationPolicy: processing track \(track.value(forKey: "track")!)")
track.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
guard let releases = track.value(forKey: #keyPath(ReleaseTrack._releases)) as? NSOrderedSet else {
// print("Source_17_1MigrationPolicy: releases not found for track: \(track.value(forKey: "track")!)")
continue
}
for case let version as NSManagedObject in releases {
// print("Source_17_1MigrationPolicy: updating sourceID for version: \(version.value(forKey: "version")!)")
version.setValue(sourceID, forKey: #keyPath(AppVersion.sourceID))
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
//
// StoreApp17To17_1MigrationPolicy.swift
// AltStore
//
// Created by Magesh K on 15/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import CoreData
fileprivate extension NSManagedObject
{
var storeAppReleaseTracks: NSOrderedSet? {
let tracks = self.value(forKey: #keyPath(StoreApp._releaseTracks)) as? NSOrderedSet
return tracks
}
}
@objc(StoreApp17To17_1MigrationPolicy)
class StoreApp17To17_1MigrationPolicy: NSEntityMigrationPolicy
{
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
}
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws
{
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
let appBundleID = dInstance.value(forKey: #keyPath(StoreApp.bundleIdentifier))
for case let track as NSManagedObject in dInstance.storeAppReleaseTracks ?? []
{
track.setValue(appBundleID, forKey: #keyPath(ReleaseTrack._appBundleID))
guard let releases = track.value(forKey: #keyPath(ReleaseTrack._releases)) as? NSOrderedSet else {
continue
}
for case let version as NSManagedObject in releases {
version.setValue(appBundleID, forKey: #keyPath(AppVersion.appBundleID))
}
}
if let permissions = dInstance.value(forKey: #keyPath(StoreApp._permissions)) as? NSSet {
for case let permission as NSManagedObject in permissions {
permission.setValue(appBundleID, forKey: #keyPath(AppPermission.appBundleID))
}
}
if let screenshots = dInstance.value(forKey: #keyPath(StoreApp._screenshots)) as? NSOrderedSet {
for case let screenshot as NSManagedObject in screenshots {
screenshot.setValue(appBundleID, forKey: #keyPath(AppScreenshot.appBundleID))
}
}
}
}

View File

@@ -75,6 +75,9 @@ public class NewsItem: BaseEntity, Decodable
self.imageURL = try container.decodeIfPresent(URL.self, forKey: .imageURL) self.imageURL = try container.decodeIfPresent(URL.self, forKey: .imageURL)
self.externalURL = try container.decodeIfPresent(URL.self, forKey: .externalURL) self.externalURL = try container.decodeIfPresent(URL.self, forKey: .externalURL)
// TODO: app specific news should be moved to appEntity (via refactoring)
// This can be done by: 1. having two newsItem schema, one for source and one for StoreApp
// 2. move this appID field into the newItem schema which is under StoreApp.
self.appID = try container.decodeIfPresent(String.self, forKey: .appID) self.appID = try container.decodeIfPresent(String.self, forKey: .appID)
let notify = try container.decodeIfPresent(Bool.self, forKey: .notify) ?? false let notify = try container.decodeIfPresent(Bool.self, forKey: .notify) ?? false

View File

@@ -14,6 +14,8 @@ public class ReleaseTrack: BaseEntity, Decodable
{ {
// attributes // attributes
@NSManaged @objc(track) public private(set) var _track: String? @NSManaged @objc(track) public private(set) var _track: String?
@NSManaged @objc(appBundleID) public private(set) var _appBundleID: String?
@NSManaged @objc(sourceID) public private(set) var _sourceID: String?
// RelationShips // RelationShips
@NSManaged @objc(releases) public private(set) var _releases: NSOrderedSet? @NSManaged @objc(releases) public private(set) var _releases: NSOrderedSet?
@@ -89,7 +91,7 @@ public extension ReleaseTrack{
} }
// update it into the appVersion // update it into the appVersion
_ = version.mutateForData(channel: track, appBundleID: storeApp.bundleIdentifier) _ = version.mutateForData(channel: track, appBundleID: storeApp.bundleIdentifier, sourceID: storeApp.sourceIdentifier)
} }
} }
@@ -109,6 +111,10 @@ public extension ReleaseTrack{
if key == NSExpression(forKeyPath: #keyPath(ReleaseTrack.storeApp)).keyPath if key == NSExpression(forKeyPath: #keyPath(ReleaseTrack.storeApp)).keyPath
{ {
updateVersions(for: storeApp) updateVersions(for: storeApp)
// update unique constraint attribs
self._appBundleID = storeApp?.bundleIdentifier
self._sourceID = storeApp?.sourceIdentifier
} }
} }
} }

View File

@@ -11,7 +11,11 @@ import UIKit
public extension Source public extension Source
{ {
static let altStoreIdentifier = try! Source.sourceID(from: Source.altStoreSourceURL) #if ALPHA
static let altStoreGroupIdentifier = Bundle.Info.appbundleIdentifier
#else
static let altStoreGroupIdentifier = Bundle.Info.appbundleIdentifier
#endif
#if STAGING #if STAGING
@@ -24,13 +28,15 @@ public extension Source
#else #else
#if ALPHA #if ALPHA
static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! static let altStoreSourceURL = URL(string: "https://sidestore.io/apps-v2.json/")!
#else #else
// static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! static let altStoreSourceURL = URL(string: "https://sidestore.io/apps-v2.json/")!
static let altStoreSourceURL = URL(string: "https://sidestore.io/apps-v2.json/")! // using v2 for alpha releases
#endif #endif
#endif #endif
// normalized url is the source identifier (or) p-key!
static let altStoreIdentifier = try! Source.sourceID(from: altStoreSourceURL)
} }
// public struct AppPermissionFeed: Codable { // public struct AppPermissionFeed: Codable {
@@ -205,7 +211,8 @@ public class Source: BaseEntity, Decodable
/* Properties */ /* Properties */
@NSManaged public var version: Int @NSManaged public var version: Int
@NSManaged public var name: String @NSManaged public var name: String
@NSManaged public private(set) var identifier: String @NSManaged public private(set) var identifier: String // NOTE: sourceID is just normalized sourceURL
@NSManaged public private(set) var groupID: String?
@NSManaged public var sourceURL: URL @NSManaged public var sourceURL: URL
/* Source Detail */ /* Source Detail */
@@ -280,6 +287,9 @@ public class Source: BaseEntity, Decodable
case news case news
case featuredApps case featuredApps
case userInfo case userInfo
// case identifier
case groupID = "identifier"
} }
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
@@ -359,6 +369,24 @@ public class Source: BaseEntity, Decodable
// Updates identifier + apps & newsItems // Updates identifier + apps & newsItems
try self.setSourceURL(sourceURL) try self.setSourceURL(sourceURL)
// NOTE: Source ID is just normalized sourceURL. coz normalized url is the primary key which needs to be unique
// Hence if a source's URL changed, then it means it is a different source now.
// This also means that the identifier field in the source is irrelevant (if any)
// if we want grouping of sources from same author or something like that then we should have used groupID (a new field)
// shouldn't use the existing "identifier" field, hence the following is commented out
// // if an explicit identifier is present, then use it
// if let identifier = try container.decodeIfPresent(String.self, forKey: .identifier)
// {
// self.identifier = identifier
// }
// if an explicit (group)identifier is present, then use it as groupID else use sourceID as groupID too
self.groupID = try container.decodeIfPresent(String.self, forKey: .groupID) ?? self.identifier
} }
catch catch
{ {
@@ -405,7 +433,7 @@ public extension Source
// TODO: Support alternate URLs // TODO: Support alternate URLs
let isRecommended = recommendedSources.contains { source in let isRecommended = recommendedSources.contains { source in
return source.identifier == self.identifier || source.sourceURL?.absoluteString.lowercased() == self.sourceURL.absoluteString return source.identifier == self.identifier || source.sourceURL?.absoluteString.lowercased() == self.sourceURL.absoluteString.lowercased()
} }
return isRecommended return isRecommended
} }
@@ -418,14 +446,17 @@ public extension Source
} }
} }
internal extension Source public extension Source
{ {
class func sourceID(from sourceURL: URL) throws -> String class func sourceID(from sourceURL: URL) throws -> String
{ {
let sourceID = try sourceURL.normalized() let sourceID = try sourceURL.normalized()
return sourceID return sourceID
} }
}
internal extension Source
{
func setFeaturedApps(_ featuredApps: [StoreApp]?) func setFeaturedApps(_ featuredApps: [StoreApp]?)
{ {
// Explicitly update relationships for all apps to ensure featuredApps merges correctly. // Explicitly update relationships for all apps to ensure featuredApps merges correctly.
@@ -451,11 +482,17 @@ public extension Source
{ {
func setSourceURL(_ sourceURL: URL) throws func setSourceURL(_ sourceURL: URL) throws
{ {
let identifier = try Source.sourceID(from: sourceURL)
self.identifier = identifier
self.sourceURL = sourceURL self.sourceURL = sourceURL
// update the normalized sourceURL as the identifier
let identifier = try Source.sourceID(from: sourceURL)
try self.setSourceID(identifier)
}
func setSourceID(_ identifier: String) throws
{
self.identifier = identifier
for app in self.apps for app in self.apps
{ {
app.sourceIdentifier = identifier app.sourceIdentifier = identifier
@@ -479,6 +516,7 @@ public extension Source
{ {
let source = Source(context: context) let source = Source(context: context)
source.name = "SideStore Offical" source.name = "SideStore Offical"
source.groupID = Source.altStoreGroupIdentifier
source.identifier = Source.altStoreIdentifier source.identifier = Source.altStoreIdentifier
try! source.setSourceURL(Source.altStoreSourceURL) try! source.setSourceURL(Source.altStoreSourceURL)
@@ -491,12 +529,13 @@ public extension Source
return source return source
} }
class func make(name: String, identifier: String, sourceURL: URL, context: NSManagedObjectContext) -> Source class func make(name: String, groupID: String, sourceURL: URL, context: NSManagedObjectContext) -> Source
{ {
let source = Source(context: context) let source = Source(context: context)
source.name = name source.name = name
source.identifier = identifier
source.sourceURL = sourceURL source.sourceURL = sourceURL
source.sourceURL = sourceURL
source.identifier = try! Source.sourceID(from: sourceURL)
return source return source
} }

View File

@@ -1,8 +1,8 @@
// Configuration settings file format documentation can be found at: // Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974 // https://help.apple.com/xcode/#/dev745c5c974
MARKETING_VERSION = 0.6.0 MARKETING_VERSION = 0.6.1
CURRENT_PROJECT_VERSION = 6000 CURRENT_PROJECT_VERSION = 0601
// Vars to be overwritten by `CodeSigning.xcconfig` if exists // Vars to be overwritten by `CodeSigning.xcconfig` if exists
DEVELOPMENT_TEAM = S32Z3HMYVQ DEVELOPMENT_TEAM = S32Z3HMYVQ

View File

@@ -28,7 +28,7 @@ Why iOS 15? Targeting such a recent version of iOS allows us to accelerate devel
SideStore is a just regular, sandboxed iOS application. The AltStore app target contains the vast majority of SideStore's functionality, including all the logic for downloading and updating apps through SideStore. SideStore makes heavy use of standard iOS frameworks and technologies most iOS developers are familiar with. SideStore is a just regular, sandboxed iOS application. The AltStore app target contains the vast majority of SideStore's functionality, including all the logic for downloading and updating apps through SideStore. SideStore makes heavy use of standard iOS frameworks and technologies most iOS developers are familiar with.
### EM Proxy ### EM Proxy
[SideServer mobile](https://github.com/jkcoxson/em_proxy) powers the defining feature of SideStore: untethered app installation. By levaraging an App Store app with additional entitlements (WireGuard) to create the VPN tunnel for us, it allows SideStore to take advantage of [Jitterbug](https://github.com/osy/Jitterbug)'s loopback method without requiring a paid developer account. [SideServer mobile](https://github.com/jkcoxson/em_proxy) powers the defining feature of SideStore: untethered app installation. By leveraging an App Store app with additional entitlements (WireGuard or StosVPN) to create the VPN tunnel for us, it allows SideStore to take advantage of [Jitterbug](https://github.com/osy/Jitterbug)'s loopback method without requiring a paid developer account.
### Minimuxer ### Minimuxer
[Minimuxer](https://github.com/jkcoxson/minimuxer) is a lockdown muxer that can run inside iOSs sandbox. It replicates Apples usbmuxd protocol on MacOS to “discover” devices to interface with wireguard On-Device. [Minimuxer](https://github.com/jkcoxson/minimuxer) is a lockdown muxer that can run inside iOSs sandbox. It replicates Apples usbmuxd protocol on MacOS to “discover” devices to interface with wireguard On-Device.

View File

@@ -0,0 +1,54 @@
//
// BuildInfo.swift
// AltStore
//
// Created by Magesh K on 23/03/25.
// Copyright © 2025 SideStore. All rights reserved.
//
import Foundation
public class BuildInfo{
private static let MARKETING_VERSION_TAG = "CFBundleShortVersionString"
private static let CURRENT_PROJECT_VERSION_TAG = kCFBundleVersionKey as String
private static let XCODE_VERSION_TAG = "DTXcode"
private static let XCODE_REVISION_TAG = "DTXcodeBuild"
let bundle: Bundle
public init(){
bundle = Bundle.main
}
enum BundleError: Swift.Error {
case invalidURL
}
public init(url: URL) throws {
guard let bundle = Bundle(url: url) else {
throw BundleError.invalidURL
}
self.bundle = bundle
}
public lazy var project_version: String? = {
let version = bundle.object(forInfoDictionaryKey: Self.CURRENT_PROJECT_VERSION_TAG) as? String
return version
}()
public lazy var marketing_version: String? = {
let version = bundle.object(forInfoDictionaryKey: Self.MARKETING_VERSION_TAG) as? String
return version
}()
public lazy var xcode: String? = {
let xcode = bundle.object(forInfoDictionaryKey: Self.XCODE_VERSION_TAG) as? String
return xcode
}()
public lazy var xcode_revision: String? = {
let revision = bundle.object(forInfoDictionaryKey: Self.XCODE_REVISION_TAG) as? String
return revision
}()
}