Skip to content

Commit bfbb469

Browse files
authored
Update installer.js
1 parent a6a997f commit bfbb469

File tree

1 file changed

+83
-8
lines changed

1 file changed

+83
-8
lines changed

web/installer.js

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ let installer = (function () {
9393
const PREFLIGHT_URL = "https://ipa.s0n1c.ca/preflight";
9494
const INSTALL_BASE = "https://ipa.s0n1c.ca";
9595
const DEFAULT_REPO = "ProStore-iOS/ProStore"; // repo to inspect by default
96+
const README_RAW = "https://raw.githubusercontent.com/ProStore-iOS/certificates/refs/heads/main/README.md";
9697

9798
// internal state
9899
let _progress = 0; // 0..100
@@ -131,13 +132,49 @@ let installer = (function () {
131132
return res.json();
132133
}
133134

135+
async function _fetchText(url, opts = {}) {
136+
const res = await fetch(url, opts);
137+
if (!res.ok) {
138+
const text = await res.text().catch(() => "");
139+
const msg = `HTTP ${res.status}${text ? " - " + text : ""}`;
140+
const e = new Error(msg);
141+
e.status = res.status;
142+
throw e;
143+
}
144+
return res.text();
145+
}
146+
147+
// Try to fetch the README and extract the Recommend Certificate short name
148+
async function _getRecommendedCertificate() {
149+
try {
150+
const raw = await _fetchText(README_RAW);
151+
// Grab the Recommend Certificate section (everything after its heading until next '---' or next heading)
152+
const sectionMatch = raw.match(/#\s*Recommend Certificate\s*([\s\S]*?)(?:\n---|\n#|$)/i);
153+
const section = sectionMatch ? sectionMatch[1] : raw;
154+
155+
// Find the first bold line inside that section: **...**
156+
const boldMatch = section.match(/\*\*(.+?)\*\*/);
157+
if (!boldMatch) return null;
158+
159+
let rec = boldMatch[1].trim();
160+
// Remove trailing " - ❌ Revoked" or any " - ..." suffix
161+
rec = rec.replace(/['"]/g, '').split(/\s*-\s*/)[0].trim();
162+
if (!rec) return null;
163+
console.log("Recommended certificate parsed from README:", rec);
164+
return rec;
165+
} catch (e) {
166+
console.warn("Failed to fetch/parse recommended certificate README:", e);
167+
return null;
168+
}
169+
}
170+
134171
return {
135172
// Return percentage (integer)
136173
getStatus: function () {
137174
return _progress;
138175
},
139176

140-
// Begin the install flow (auto-select latest release & preferred asset)
177+
// Begin the install flow (auto-select release & preferred asset)
141178
// options: { repo: "owner/repo", token: "GITHUB_PAT (optional)", preferPrerelease: false }
142179
// Returns a Promise that resolves to the final preflight response object when finished.
143180
beginInstall: async function (options = {}) {
@@ -174,29 +211,67 @@ let installer = (function () {
174211
.filter(r => preferPrerelease ? true : !r.prerelease)
175212
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
176213

214+
// If no visible after filtering, fallback to non-draft
215+
let defaultRelease = null;
177216
if (!visible.length) {
178-
// if strict filter removed everything, try less strict (non-draft)
179217
const fallback = releases.filter(r => !r.draft).sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
180218
if (!fallback.length) throw new Error("No suitable releases found (all drafts?).");
181-
_releaseInfo = fallback[0];
219+
defaultRelease = fallback[0];
182220
} else {
183-
_releaseInfo = visible[0]; // latest
221+
defaultRelease = visible[0];
184222
}
185223

186224
_setProgress(30);
187225

226+
// TRY: get recommended certificate name from README and find matching release
227+
let chosenRelease = null;
228+
try {
229+
const recommended = await _getRecommendedCertificate();
230+
if (recommended) {
231+
// Try to find a release that mentions the recommended certificate in name, tag_name or body
232+
const found = releases.find(r => {
233+
const hay = ((r.name || "") + " " + (r.tag_name || "") + " " + (r.body || "")).toLowerCase();
234+
return hay.includes(recommended.toLowerCase());
235+
});
236+
if (found) {
237+
chosenRelease = found;
238+
console.log("Using release matched to recommended certificate:", chosenRelease.name || chosenRelease.tag_name);
239+
} else {
240+
console.log("Recommended certificate not found in releases; will fall back to latest release.");
241+
}
242+
} else {
243+
console.log("No recommended certificate parsed; using latest release fallback.");
244+
}
245+
} catch (e) {
246+
console.warn("Error while trying to apply recommended certificate logic:", e);
247+
}
248+
249+
// If we didn't pick a recommended release, use the default latest/visible
250+
_releaseInfo = chosenRelease || defaultRelease;
251+
252+
_setProgress(45);
253+
188254
// pick an asset (prefer "signed" .ipa)
189-
const chosen = _chooseAssetFromRelease(_releaseInfo);
190-
if (!chosen) throw new Error("No .ipa assets found in the latest release.");
255+
let chosen = _chooseAssetFromRelease(_releaseInfo);
256+
if (!chosen) {
257+
// If the chosen release didn't have an ipa, try to fallback to the visible list to find any release with an .ipa
258+
const otherWithIpa = (visible.length ? visible : releases).find(r => _chooseAssetFromRelease(r));
259+
if (otherWithIpa) {
260+
_releaseInfo = otherWithIpa;
261+
chosen = _chooseAssetFromRelease(otherWithIpa);
262+
}
263+
}
264+
265+
if (!chosen) throw new Error("No .ipa assets found in the selected release(s).");
191266
_chosenAsset = chosen;
192267

193-
_setProgress(45);
268+
_setProgress(60);
194269

195270
// Prepare signing using preflight endpoint (same as original flow)
196271
const ipaUrl = chosen.browser_download_url;
197272
if (!ipaUrl) throw new Error("Chosen asset has no browser_download_url.");
198273

199-
_setProgress(60);
274+
_setProgress(75);
200275

201276
const resp = await fetch(PREFLIGHT_URL, {
202277
method: "POST",

0 commit comments

Comments
 (0)