Skip to content

Commit 43eaa99

Browse files
committed
Only save blobs if not already saved in blobs directory (#513)
This setting can be changed from the Help menu
1 parent 9099daa commit 43eaa99

File tree

5 files changed

+71
-15
lines changed

5 files changed

+71
-15
lines changed

src/main/java/airsquared/blobsaver/app/Controller.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ private void loadSavedDevice(Prefs.SavedDevice savedDevice) {
197197
deleteDeviceMenu.setText("Remove Saved Device");
198198
return;
199199
}
200-
deleteDeviceMenu.setText("Remove Saved Device \"" + savedDevice + "\"");
200+
deleteDeviceMenu.setText("Remove \"" + savedDevice + "\"");
201201

202202
ecidField.setText(savedDevice.getEcid());
203203
pathField.setText(savedDevice.getSavePath());
@@ -307,6 +307,10 @@ public void disableAnalyticsHandler(Event evt) {
307307
Prefs.setDisableAnalytics(((CheckMenuItem) evt.getSource()).isSelected());
308308
}
309309

310+
public void alwaysSaveNewBlobsHandler(Event evt) {
311+
Prefs.setAlwaysSaveNewBlobs(((CheckMenuItem) evt.getSource()).isSelected());
312+
}
313+
310314
public void checkBlobs() {
311315
Utils.openURL("https://verify.shsh.host");
312316
Analytics.checkBlobs();
@@ -380,7 +384,7 @@ private void useMacOSMenuBar() {
380384
new SeparatorMenuItem(), tk.createBringAllToFrontItem());
381385
tk.autoAddWindowMenuItems(menuBar.getMenus().get(3));
382386

383-
menuBar.getMenus().get(4).getItems().remove(10); // remove about
387+
menuBar.getMenus().get(4).getItems().remove(11); // remove about
384388

385389
tk.setApplicationMenu(applicationMenu);
386390
tk.setGlobalMenuBar(menuBar);

src/main/java/airsquared/blobsaver/app/Prefs.java

+8
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ public static void setDarkMode(DarkMode darkMode) {
141141
appPrefs.put("Dark Mode", darkMode.name());
142142
}
143143

144+
public static boolean getAlwaysSaveNewBlobs() {
145+
return appPrefs.getBoolean("Always save new blobs", false);
146+
}
147+
148+
public static void setAlwaysSaveNewBlobs(boolean alwaysSaveNewBlobs) {
149+
appPrefs.putBoolean("Always save new blobs", alwaysSaveNewBlobs);
150+
}
151+
144152
private static Stream<SavedDevice> savedDevices() {
145153
try {
146154
return Arrays.stream(savedDevicesPrefs.childrenNames()).map(SavedDevice::new);

src/main/java/airsquared/blobsaver/app/TSS.java

+46-11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.List;
3838
import java.util.Map;
3939
import java.util.Objects;
40+
import java.util.StringJoiner;
4041
import java.util.regex.Pattern;
4142
import java.util.stream.Stream;
4243

@@ -46,6 +47,7 @@
4647
import static airsquared.blobsaver.app.Utils.getFirmwareList;
4748
import static airsquared.blobsaver.app.Utils.getSignedBetas;
4849
import static airsquared.blobsaver.app.Utils.getSignedFirmwares;
50+
import static airsquared.blobsaver.app.Utils.isNumeric;
4951

5052
public class TSS extends Task<String> {
5153

@@ -95,13 +97,14 @@ protected String call() throws TSSException {
9597
System.out.println("iosVersions = " + iosVersions);
9698
ArrayList<String> args = constructArgs();
9799

98-
StringBuilder responseBuilder = new StringBuilder("Successfully saved blobs in\n").append(savePath);
99-
if (manualIpswURL == null) {
100-
responseBuilder.append(iosVersions.size() == 1 ? "\n\nFor version " : "\n\nFor versions ");
101-
}
102-
103-
// can't use forEach() because exception won't be caught
100+
var alreadySaved = new StringJoiner(", ");
101+
var savedFor = new StringJoiner(", ");
104102
for (Utils.IOSVersion iosVersion : iosVersions) {
103+
if (!Prefs.getAlwaysSaveNewBlobs() && checkAlreadySaved(iosVersion)) {
104+
alreadySaved.add(iosVersion.versionString());
105+
continue;
106+
}
107+
105108
try {
106109
saveFor(iosVersion, args);
107110
} catch (TSSException e) {
@@ -113,11 +116,22 @@ protected String call() throws TSSException {
113116
}
114117

115118
if (iosVersion.versionString() != null) {
116-
responseBuilder.append(iosVersion.versionString());
117-
if (iosVersion != iosVersions.get(iosVersions.size() - 1))
118-
responseBuilder.append(", ");
119+
savedFor.add(iosVersion.versionString());
119120
}
120121
}
122+
StringBuilder responseBuilder = new StringBuilder();
123+
if (manualIpswURL != null || savedFor.length() > 0) {
124+
responseBuilder.append("Successfully saved blobs in\n").append(savePath);
125+
if (savedFor.length() > 0) {
126+
responseBuilder.append("\n\nFor version").append(iosVersions.size() == 1 ? " " : "s ").append(savedFor);
127+
}
128+
if (alreadySaved.length() > 0) {
129+
responseBuilder.append("\n\n");
130+
}
131+
}
132+
if (alreadySaved.length() > 0) {
133+
responseBuilder.append("Already saved for ").append(alreadySaved);
134+
}
121135

122136
if (saveToTSSSaver || saveToSHSHHost) {
123137
responseBuilder.append("\n\n");
@@ -133,6 +147,27 @@ protected String call() throws TSSException {
133147
return responseBuilder.toString();
134148
}
135149

150+
private boolean checkAlreadySaved(Utils.IOSVersion ios) {
151+
if (ios.versionString() == null) {
152+
return false;
153+
}
154+
var versionStringOnly = ios.versionString().trim().replaceFirst(" .*", ""); // strip out 'beta' labels
155+
// https://github.com/1Conan/tsschecker/blob/0bc6174c3c2f77a0de525b71e7d8ec0987f07aa1/tsschecker/tsschecker.c#L1262
156+
String fileName = "%s_%s_%s_%s-%s_%s.shsh2"
157+
.formatted(parseECID(), deviceIdentifier, getBoardConfig(), versionStringOnly, ios.buildid(), apnonce);
158+
159+
if (Files.exists(Path.of(savePath, fileName))) {
160+
System.out.println("Already Saved: " + fileName);
161+
return true;
162+
}
163+
return false;
164+
}
165+
166+
private long parseECID() {
167+
return isNumeric(ecid) ? Long.parseLong(ecid)
168+
: Long.parseLong(ecid.startsWith("0x") ? ecid.substring(2) : ecid, 16);
169+
}
170+
136171

137172
private void saveFor(Utils.IOSVersion iosVersion, ArrayList<String> args) throws TSSException {
138173
final int urlIndex = args.size() - 1;
@@ -203,7 +238,7 @@ private List<Utils.IOSVersion> getIOSVersions() throws TSSException {
203238
manualVersion.equals(iosVersion.versionString())).findFirst()
204239
.orElseThrow(() -> new TSSException("No versions found.", false)));
205240
} else if (manualIpswURL != null) {
206-
return Collections.singletonList(new Utils.IOSVersion(null, manualIpswURL, null));
241+
return Collections.singletonList(new Utils.IOSVersion(null, null, manualIpswURL, null));
207242
} else if (includeBetas) {
208243
return Stream.concat(getSignedFirmwares(deviceIdentifier), getSignedBetas(deviceIdentifier)).toList();
209244
} else { // all signed firmwares
@@ -391,7 +426,7 @@ public void showErrorAlert() {
391426
private void saveBlobsTSSSaver(StringBuilder responseBuilder) {
392427
Map<Object, Object> deviceParameters = new HashMap<>();
393428

394-
deviceParameters.put("ecid", String.valueOf(Long.parseLong(ecid.startsWith("0x") ? ecid.substring(2) : ecid, 16)));
429+
deviceParameters.put("ecid", String.valueOf(parseECID()));
395430
deviceParameters.put("deviceIdentifier", deviceIdentifier);
396431
deviceParameters.put("boardConfig", getBoardConfig());
397432

src/main/java/airsquared/blobsaver/app/Utils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ static Stream<IOSVersion> getBetaList(String deviceIdentifier) throws IOExceptio
354354
private static Stream<IOSVersion> createVersionStream(JsonArray array) {
355355
return StreamSupport.stream(array.spliterator(), false)
356356
.map(JsonElement::getAsJsonObject)
357-
.map(o -> new IOSVersion(o.get("version").getAsString(), o.get("url").getAsString(), o.get("signed").getAsBoolean()));
357+
.map(o -> new IOSVersion(o.get("version").getAsString(), o.get("buildid").getAsString(), o.get("url").getAsString(), o.get("signed").getAsBoolean()));
358358
}
359359

360360
static Stream<IOSVersion> getSignedFirmwares(String deviceIdentifier) throws IOException {
@@ -365,7 +365,7 @@ static Stream<IOSVersion> getSignedBetas(String deviceIdentifier) throws IOExcep
365365
return getBetaList(deviceIdentifier).filter(IOSVersion::signed);
366366
}
367367

368-
record IOSVersion(String versionString, String ipswURL, Boolean signed) {
368+
record IOSVersion(String versionString, String buildid, String ipswURL, Boolean signed) {
369369
public IOSVersion {
370370
Objects.requireNonNull(ipswURL, "ipsw url cannot be null");
371371
}

src/main/resources/airsquared/blobsaver/app/blobsaver.fxml

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@
8181
<Prefs fx:factory="getDisableAnalytics"/>
8282
</selected>
8383
</CheckMenuItem>
84+
<CheckMenuItem mnemonicParsing="false" text="Always Save New Blobs"
85+
onAction="#alwaysSaveNewBlobsHandler">
86+
<selected>
87+
<Prefs fx:factory="getAlwaysSaveNewBlobs"/>
88+
</selected>
89+
</CheckMenuItem>
8490
<SeparatorMenuItem mnemonicParsing="false"/>
8591
<MenuItem mnemonicParsing="false" onAction="#showWiki" text="blobsaver Help/Wiki"/>
8692
<MenuItem mnemonicParsing="false" onAction="#newGithubIssue" text="Send Feedback (Github Issue)"/>
@@ -312,6 +318,9 @@
312318
<VBox.margin>
313319
<Insets bottom="15.0"/>
314320
</VBox.margin>
321+
<contextMenu>
322+
<ContextMenu items="$deleteDeviceMenu"/>
323+
</contextMenu>
315324
</ListView>
316325
<!--suppress JavaFxUnresolvedFxIdReference -->
317326
<Button fx:id="saveDeviceButton" prefWidth="Infinity" maxWidth="Infinity" mnemonicParsing="false"

0 commit comments

Comments
 (0)