Skip to content

Commit f3a1d21

Browse files
Use codable to decode/encode manifest plist
1 parent e2b6d09 commit f3a1d21

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

Sources/App/Controllers/InstallController.swift

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -66,64 +66,49 @@ struct InstallController: RouteCollection {
6666
}
6767

6868
do {
69-
var format = PropertyListSerialization.PropertyListFormat.xml
70-
let plistAny = try PropertyListSerialization.propertyList(from: data, options: [], format: &format)
71-
guard var plist = plistAny as? [String: Any] else {
69+
let decoder = PropertyListDecoder()
70+
let ipaManifest = try decoder.decode(IPAManifest.self, from: data)
71+
guard var ipaItem = ipaManifest.items.first, var ipaAsset = ipaItem.assets.first else {
7272
return nil
7373
}
7474

75-
// Navigate to the first asset URL
76-
guard var items = plist["items"] as? [[String: Any]], !items.isEmpty else {
75+
guard var ipaURLComponents = URLComponents(string: ipaAsset.url) else {
7776
return nil
7877
}
7978

80-
var firstItem = items[0]
81-
guard var assets = firstItem["assets"] as? [[String: Any]], !assets.isEmpty else {
82-
return nil
83-
}
84-
85-
var firstAsset = assets[0]
86-
guard let urlString = firstAsset["url"] as? String, var urlComponents = URLComponents(string: urlString) else {
87-
return nil
88-
}
89-
90-
// Update host if needed
91-
if urlComponents.host == "dl.dropboxusercontent.com" {
92-
urlComponents.host = "www.dropbox.com"
79+
if ipaURLComponents.host == "dl.dropboxusercontent.com" {
80+
ipaURLComponents.host = "www.dropbox.com"
9381
}
9482

95-
// ensure dl=1 is present to force direct download from Dropbox
96-
var queryItems = urlComponents.queryItems ?? []
83+
var queryItems = ipaURLComponents.queryItems ?? []
9784
let dlQueryItem = URLQueryItem(name: "dl", value: "1")
98-
if let dlQueryItemIndex = queryItems.firstIndex(where: { $0.name == dlQueryItem.name }) {
99-
queryItems[dlQueryItemIndex] = dlQueryItem
85+
if let index = queryItems.firstIndex(where: { $0.name == "dl" }) {
86+
queryItems[index] = dlQueryItem
10087
} else {
10188
queryItems.append(dlQueryItem)
10289
}
103-
urlComponents.queryItems = queryItems
104-
105-
// Set the modified URL back to the first asset
106-
if let newURL = urlComponents.string {
107-
firstAsset["url"] = newURL
108-
assets[0] = firstAsset
109-
firstItem["assets"] = assets
110-
items[0] = firstItem
111-
plist["items"] = items
112-
} else {
90+
ipaURLComponents.queryItems = queryItems
91+
92+
guard let newIPAURL = ipaURLComponents.string else {
11393
return nil
11494
}
11595

116-
// Serialize the modified plist back to Data
117-
let newData = try PropertyListSerialization.data(
118-
fromPropertyList: plist,
119-
format: .xml,
120-
options: 0
121-
)
96+
ipaAsset.url = newIPAURL
97+
98+
// Rebuild updated manifest
99+
var updatedIPAManifest = ipaManifest
100+
ipaItem.assets[0] = ipaAsset
101+
updatedIPAManifest.items[0] = ipaItem
102+
103+
let encoder = PropertyListEncoder()
104+
encoder.outputFormat = .xml
105+
let newData = try encoder.encode(updatedIPAManifest)
106+
122107
var newBuffer = ByteBufferAllocator().buffer(capacity: newData.count)
123108
newBuffer.writeBytes(newData)
124109
return newBuffer
125110
} catch {
126-
logger.error("Manifest plist modification failed: \(error.localizedDescription). \nRaw error: \(error)")
111+
logger.error("Manifest plist modification failed: \(error.localizedDescription).")
127112
return nil
128113
}
129114
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// IPAManifest.swift
3+
// install-helper
4+
//
5+
// Created by Vineet Choudhary on 14/09/25.
6+
//
7+
8+
import Foundation
9+
10+
struct IPAManifest: Codable {
11+
var items: [Item]
12+
13+
struct Item: Codable {
14+
var assets: [Asset]
15+
var metadata: Metadata?
16+
17+
struct Asset: Codable {
18+
var kind: String
19+
var url: String
20+
}
21+
22+
struct Metadata: Codable {
23+
var bundleIdentifier: String?
24+
var bundleVersion: String?
25+
var kind: String?
26+
var title: String?
27+
28+
private enum CodingKeys: String, CodingKey {
29+
case bundleIdentifier = "bundle-identifier"
30+
case bundleVersion = "bundle-version"
31+
case kind
32+
case title
33+
}
34+
}
35+
36+
}
37+
38+
}
39+

0 commit comments

Comments
 (0)