Skip to content

Commit 86c7d0e

Browse files
committedMar 26, 2023
Be more conservative about reprovisioning in anisette-server
1 parent 28b8890 commit 86c7d0e

File tree

3 files changed

+181
-84
lines changed

3 files changed

+181
-84
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
bin/
2+
.dub/

‎anisette_server/app.d

+72-46
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import handy_httpd;
2+
import handy_httpd.components.request;
23
import std.algorithm.searching;
34
import std.array;
45
import std.base64;
@@ -17,6 +18,7 @@ import constants;
1718

1819
static __gshared ADI* adi;
1920
static __gshared ulong rinfo;
21+
static __gshared bool allowRemoteProvisioning = false;
2022

2123
void main(string[] args) {
2224
auto serverConfig = ServerConfig.defaultValues;
@@ -35,6 +37,7 @@ void main(string[] args) {
3537
"a|adi-path", format!"Where the provisioning information should be stored on the computer (default: %s)"(path), &path,
3638
"init-only", format!"Download libraries and exit (default: %s)"(onlyInit), &onlyInit,
3739
"can-download", format!"If turned on, may download the dependencies automatically (default: %s)"(apkDownloadAllowed), &apkDownloadAllowed,
40+
"allow-remote-reprovisioning", format!"If turned on, the server may reprovision the server on client demand (default: %s)"(allowRemoteProvisioning), &allowRemoteProvisioning,
3841
);
3942

4043
if (helpInformation.helpWanted) {
@@ -102,57 +105,80 @@ void main(string[] args) {
102105

103106
auto s = new HttpServer((ref ctx) {
104107
auto req = ctx.request;
105-
auto res = ctx.response;
106-
res.addHeader("Implementation-Version", anisetteServerBranding ~ " " ~ anisetteServerVersion);
108+
ctx.response.addHeader("Implementation-Version", anisetteServerBranding ~ " " ~ anisetteServerVersion);
109+
110+
writeln("[<<] ", req.method, " ", req.url);
111+
if (req.method != "GET") {
112+
writefln("[>>] 405 Method Not Allowed");
113+
ctx.response.setStatus(405).setStatusText("Method Not Allowed").flushHeaders();
114+
return;
115+
}
116+
107117
if (req.url == "/reprovision") {
108-
writeln("[<<] GET /reprovision");
109-
adi.provisionDevice(rinfo);
110-
writeln("[>>] 200 OK");
111-
res.setStatus(200);
112-
} else {
118+
if (allowRemoteProvisioning) {
119+
adi.provisionDevice(rinfo);
120+
writeln("[>>] 200 OK");
121+
ctx.response.setStatus(200);
122+
} else {
123+
writeln("[>>] 403 Forbidden");
124+
ctx.response.setStatus(403).setStatusText("Forbidden").flushHeaders();
125+
}
126+
return;
127+
}
128+
129+
if (req.url != "") {
130+
writeln("[>>] 404 Not Found");
131+
ctx.response.setStatus(404).setStatusText("Not Found").flushHeaders();
132+
return;
133+
}
134+
135+
try {
136+
import std.datetime.systime;
137+
import std.datetime.timezone;
138+
import core.time;
139+
auto time = Clock.currTime();
140+
141+
ubyte[] mid;
142+
ubyte[] otp;
113143
try {
114-
import std.datetime.systime;
115-
import std.datetime.timezone;
116-
import core.time;
117-
auto time = Clock.currTime();
118-
119-
writefln("[<<] GET /");
120-
121-
ubyte[] mid;
122-
ubyte[] otp;
123-
try {
124-
adi.getOneTimePassword(mid, otp);
125-
} catch (Throwable) {
126-
writeln("Reprovision needed.");
127-
adi.provisionDevice(rinfo);
128-
adi.getOneTimePassword(mid, otp);
144+
adi.getOneTimePassword(mid, otp);
145+
} catch (AnisetteException exception) {
146+
if (exception.anisetteError() != AnisetteError.notProvisioned) {
147+
throw exception;
129148
}
130149

131-
import std.conv;
132-
import std.json;
133-
134-
JSONValue response = [
135-
"X-Apple-I-Client-Time": time.toISOExtString.split('.')[0] ~ "Z",
136-
"X-Apple-I-MD": Base64.encode(otp),
137-
"X-Apple-I-MD-M": Base64.encode(mid),
138-
"X-Apple-I-MD-RINFO": to!string(rinfo),
139-
"X-Apple-I-MD-LU": adi.localUserUUID,
140-
"X-Apple-I-SRL-NO": adi.serialNo,
141-
"X-MMe-Client-Info": adi.clientInfo,
142-
"X-Apple-I-TimeZone": time.timezone.dstName,
143-
"X-Apple-Locale": "en_US",
144-
"X-Mme-Device-Id": adi.deviceId,
145-
];
146-
147-
writefln!"[>>] 200 OK %s"(response);
148-
149-
res.setStatus(200);
150-
res.addHeader("Content-Type", "application/json");
151-
res.writeBodyString(response.toString(JSONOptions.doNotEscapeSlashes));
152-
} catch(Throwable t) {
153-
res.setStatus(500);
154-
res.writeBodyString(t.toString());
150+
writeln("Machine wasn't provisioned??");
151+
adi.provisionDevice(rinfo);
152+
adi.getOneTimePassword(mid, otp); // if it rethrows an error, we can't do much anyway.
155153
}
154+
155+
import std.conv;
156+
import std.json;
157+
158+
JSONValue response = [
159+
"X-Apple-I-Client-Time": time.toISOExtString.split('.')[0] ~ "Z",
160+
"X-Apple-I-MD": Base64.encode(otp),
161+
"X-Apple-I-MD-M": Base64.encode(mid),
162+
"X-Apple-I-MD-RINFO": to!string(rinfo),
163+
"X-Apple-I-MD-LU": adi.localUserUUID,
164+
"X-Apple-I-SRL-NO": adi.serialNo,
165+
"X-MMe-Client-Info": adi.clientInfo,
166+
"X-Apple-I-TimeZone": time.timezone.dstName,
167+
"X-Apple-Locale": "en_US",
168+
"X-Mme-Device-Id": adi.deviceId,
169+
];
170+
ctx.response.addHeader("Content-Type", "application/json");
171+
ctx.response.writeBodyString(response.toString(JSONOptions.doNotEscapeSlashes));
172+
173+
writefln!"[>>] 200 OK %s"(response);
174+
ctx.response.okResponse();
175+
} catch(Throwable t) {
176+
string exception = t.toString();
177+
writeln("Encountered an error: ", exception);
178+
writeln("[>>] 500 Internal Server Error");
179+
ctx.response.writeBodyString(exception);
180+
181+
ctx.response.setStatus(500).setStatusText("Internal Server Error").flushHeaders();
156182
}
157183
}, serverConfig);
158184

‎lib/provision/adi.d

+108-38
Original file line numberDiff line numberDiff line change
@@ -447,47 +447,117 @@ enum string libraryPath = "lib/" ~ architectureIdentifier ~ "/";
447447
}
448448
}
449449

450-
public class AnisetteException: Exception {
451-
this(int error, string file = __FILE__, size_t line = __LINE__) {
452-
super(format!"ADI error: %s."(translateADIErrorCode(error)), file, line);
450+
enum AnisetteError: int {
451+
invalidParams = -45001,
452+
invalidParams2 = -45002,
453+
invalidTrustKey = -45003,
454+
ptmTkNotMatchingState = -45006,
455+
invalidInputDataParamHeader = -45018,
456+
unknownAdiFunction = -45019,
457+
invalidInputDataParamBody = -45020,
458+
unknownSession = -45025,
459+
emptySession = -45026,
460+
invalidDataHeader = -45031,
461+
dataTooShort = -45032,
462+
invalidDataBody = -45033,
463+
unknownADICallFlags = -45034,
464+
timeError = -45036,
465+
emptyHardwareIds = -45046,
466+
filesystemError = -45054,
467+
notProvisioned = -45061,
468+
noProvisioningToErase = -45062,
469+
pendingSession = -45063,
470+
sessionAlreadyDone = -45066,
471+
libraryLoadingFailed = -45075,
472+
}
473+
474+
string toString(AnisetteError error) {
475+
string formatString;
476+
switch (cast(int) error) {
477+
case -45001:
478+
formatString = "invalid parameters (%d)";
479+
break;
480+
case -45002:
481+
formatString = "invalid parameters (for decipher) (%d)";
482+
break;
483+
case -45003:
484+
formatString = "invalid Trust Key (%d)";
485+
break;
486+
case -45006:
487+
formatString = "ptm and tk are not matching the transmitted cpim (%d)";
488+
break;
489+
// -45017: exists (observed: iOS), unknown meaning
490+
case -45018:
491+
formatString = "invalid input data header (first uint) (pointer is correct tho) (%d)";
492+
break;
493+
case -45019:
494+
formatString = "vdfut768ig doesn't know the asked function (%d)";
495+
break;
496+
case -45020:
497+
formatString = "invalid input data (not the first uint) (%d)";
498+
break;
499+
case -45025:
500+
formatString = "unknown session (%d)";
501+
break;
502+
case -45026:
503+
formatString = "empty session (%d)";
504+
break;
505+
case -45031:
506+
formatString = "invalid data (header) (%d)";
507+
break;
508+
case -45032:
509+
formatString = "data too short (%d)";
510+
break;
511+
case -45033:
512+
formatString = "invalid data (body) (%d)";
513+
break;
514+
case -45034:
515+
formatString = "unknown ADI call flags (%d)";
516+
break;
517+
case -45036:
518+
formatString = "time error (%d)";
519+
break;
520+
// -45044: exists (observed: macOS iTunes, from Google), unknown meaning
521+
// -45045: probably a typo of -45054
522+
case -45046:
523+
formatString = "identifier generation failure: empty hardware ids (%d)";
524+
break;
525+
// -45048: exists (observed: windows iTunes, from Google), unknown meaning, resolved by adi file suppression
526+
case -45054:
527+
formatString = "generic libc/file manipulation error (%d)";
528+
break;
529+
case -45061:
530+
formatString = "not provisioned (%d)";
531+
break;
532+
case -45062:
533+
formatString = "cannot erase provisioning: not provisioned (%d)";
534+
break;
535+
case -45063:
536+
formatString = "provisioning first step is already pending (%d)";
537+
break;
538+
case -45066:
539+
formatString = "2nd step fail: session already consumed (%d)";
540+
break;
541+
case -45075:
542+
formatString = "library loading error (%d)";
543+
break;
544+
// -45076: exists (observed: macOS iTunes, from Google), unknown meaning, seems related to backward compatibility between 12.6.x and 12.7
545+
default:
546+
formatString = "unknown ADI error (%d)";
547+
break;
453548
}
549+
return format(formatString, error);
454550
}
455551

456-
enum knownErrorCodes = [
457-
-45001: "invalid parameters",
458-
-45002: "invalid parameters (for decipher)",
459-
-45003: "invalid Trust Key",
460-
-45006: "ptm and tk are not matching the transmitted cpim",
461-
// -45017: exists (observed: iOS), unknown meaning
462-
-45018: "invalid input data header (first uint) (pointer is correct tho)",
463-
-45019: "vdfut768ig doesn't know the asked function",
464-
-45020: "invalid input data (not the first uint)",
465-
-45025: "unknown session",
466-
-45026: "empty session",
467-
-45031: "invalid data (header)",
468-
-45032: "data too short",
469-
-45033: "invalid data (body)",
470-
-45034: "unknown ADI call flags",
471-
-45036: "time error",
472-
// -45044: exists (observed: macOS iTunes, from Google), unknown meaning
473-
// -45045: probably a typo of -45054
474-
-45046: "identifier generation failure: empty hardware ids",
475-
// -45048: exists (observed: windows iTunes, from Google), unknown meaning, resolved by adi file suppression
476-
-45054: "generic libc/file manipulation error",
477-
-45061: "not provisioned",
478-
-45062: "cannot erase provisioning: not provisioned",
479-
-45063: "provisioning first step is already pending",
480-
-45066: "2nd step fail: session already consumed",
481-
-45075: "library loading error",
482-
// -45076: exists (observed: macOS iTunes, from Google), unknown meaning, seems related to backward compatibility between 12.6.x and 12.7
483-
];
484-
485-
string translateADIErrorCode(int errorCode) {
486-
foreach (knownErrorCode; knownErrorCodes.byKeyValue) {
487-
if (errorCode == knownErrorCode.key) {
488-
return format!"%s (%d)"(knownErrorCode.value, errorCode);
489-
}
552+
public class AnisetteException: Exception {
553+
private AnisetteError errorCode;
554+
555+
this(int error, string file = __FILE__, size_t line = __LINE__) {
556+
this.errorCode = cast(AnisetteError) error;
557+
super(errorCode.toString(), file, line);
490558
}
491559

492-
return format!"%d"(errorCode);
560+
AnisetteError anisetteError() {
561+
return errorCode;
562+
}
493563
}

0 commit comments

Comments
 (0)
Please sign in to comment.