mirror of https://github.com/YTVanced/VancedMicroG
Add initial (non-functional) implementation of SafetyNet
SafetyNet requires DroidGuard for full functionality, see #181
This commit is contained in:
parent
190a031662
commit
b33e43c1f6
|
@ -133,7 +133,10 @@
|
|||
android:name="org.microg.gms.wearable.location.WearableLocationService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED"/>
|
||||
<data android:scheme="wear" android:host="*" android:pathPrefix="/com/google/android/location/fused/wearable" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/com/google/android/location/fused/wearable"
|
||||
android:scheme="wear"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
|
@ -282,6 +285,12 @@
|
|||
android:value="1"/>
|
||||
</service>
|
||||
|
||||
<service android:name=".auth.FirebaseAuthService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.auth.api.gms.service.START"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name="org.microg.tools.AccountPickerActivity"
|
||||
android:excludeFromRecents="true"
|
||||
|
@ -442,6 +451,12 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name="org.microg.gms.snet.SafetyNetClientService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.safetynet.service.START"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name="org.microg.gms.DummyService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.plus.service.START"/>
|
||||
|
@ -468,7 +483,6 @@
|
|||
<action android:name="com.google.android.gms.usagereporting.service.START"/>
|
||||
<action android:name="com.google.android.gms.kids.service.START"/>
|
||||
<action android:name="com.google.android.gms.common.download.START"/>
|
||||
<action android:name="com.google.android.gms.safetynet.service.START"/>
|
||||
<action android:name="com.google.android.contextmanager.service.ContextManagerService.START"/>
|
||||
<action android:name="com.google.android.gms.audiomodem.service.AudioModemService.START"/>
|
||||
<action android:name="com.google.android.gms.nearby.sharing.service.NearbySharingService.START"/>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2013-2016 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.google.android.gms.common.internal.GetServiceRequest;
|
||||
import com.google.android.gms.common.internal.IGmsCallbacks;
|
||||
|
||||
import org.microg.gms.BaseService;
|
||||
import org.microg.gms.common.GmsService;
|
||||
|
||||
public class SafetyNetClientService extends BaseService {
|
||||
|
||||
public SafetyNetClientService() {
|
||||
super("GmsSafetyNetClientSvc", GmsService.SAFETY_NET_CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {
|
||||
callback.onPostInitComplete(0, new SafetyNetClientServiceImpl(this, request.packageName), null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Copyright 2013-2016 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.safetynet.AttestationData;
|
||||
import com.google.android.gms.safetynet.HarmfulAppsData;
|
||||
import com.google.android.gms.safetynet.internal.ISafetyNetCallbacks;
|
||||
import com.google.android.gms.safetynet.internal.ISafetyNetService;
|
||||
import com.squareup.wire.Wire;
|
||||
|
||||
import org.microg.gms.common.Constants;
|
||||
import org.microg.gms.common.PackageUtils;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public class SafetyNetClientServiceImpl extends ISafetyNetService.Stub {
|
||||
private static final String TAG = "GmsSafetyNetClientImpl";
|
||||
public static final String ATTEST_URL = "https://www.googleapis.com/androidcheck/v1/attestations/attest?alt=PROTO&key=AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA";
|
||||
|
||||
private Context context;
|
||||
private String packageName;
|
||||
|
||||
public SafetyNetClientServiceImpl(Context context, String packageName) {
|
||||
this.context = context;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
private ByteString getPackageFileDigest() {
|
||||
try {
|
||||
FileInputStream is = new FileInputStream(new File(context.getPackageManager().getApplicationInfo(packageName, 0).sourceDir));
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] data = new byte[16384];
|
||||
while (true) {
|
||||
int read = is.read(data);
|
||||
if (read < 0) break;
|
||||
digest.update(data, 0, read);
|
||||
}
|
||||
return ByteString.of(digest.digest());
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
private List<ByteString> getPackageSignatures() {
|
||||
try {
|
||||
PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
||||
ArrayList<ByteString> res = new ArrayList<>();
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
for (Signature signature : pi.signatures) {
|
||||
res.add(ByteString.of(digest.digest(signature.toByteArray())));
|
||||
}
|
||||
return res;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attest(final ISafetyNetCallbacks callbacks, final byte[] nonce) throws RemoteException {
|
||||
if (nonce == null) {
|
||||
callbacks.onAttestationData(new Status(10), null);
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SafetyNetData payload = new SafetyNetData.Builder()
|
||||
.nonce(ByteString.of(nonce))
|
||||
.currentTimeMs(System.currentTimeMillis())
|
||||
.packageName(packageName)
|
||||
.fileDigest(getPackageFileDigest())
|
||||
.signatureDigest(getPackageSignatures())
|
||||
.gmsVersionCode(Constants.MAX_REFERENCE_VERSION)
|
||||
.googleCn(false)
|
||||
.seLinuxState(new SELinuxState(true, true))
|
||||
.suCandidates(Collections.<FileState>emptyList())
|
||||
.build();
|
||||
|
||||
AttestRequest request = new AttestRequest(ByteString.of(payload.toByteArray()), "");
|
||||
|
||||
Log.d(TAG, "attest: " + payload);
|
||||
|
||||
try {
|
||||
try {
|
||||
AttestResponse response = attest(request);
|
||||
callbacks.onAttestationData(Status.SUCCESS, new AttestationData(response.result));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
callbacks.onAttestationData(Status.INTERNAL_ERROR, null);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private AttestResponse attest(AttestRequest request) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(ATTEST_URL).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestProperty("Content-type", "application/x-protobuf");
|
||||
connection.setRequestProperty("Content-Encoding", "gzip");
|
||||
connection.setRequestProperty("Accept-Encoding", "gzip");
|
||||
connection.setRequestProperty("User-Agent", "SafetyNet/" + Constants.MAX_REFERENCE_VERSION);
|
||||
|
||||
Log.d(TAG, "-- Request --\n" + request);
|
||||
OutputStream os = new GZIPOutputStream(connection.getOutputStream());
|
||||
os.write(request.toByteArray());
|
||||
os.close();
|
||||
|
||||
if (connection.getResponseCode() != 200) {
|
||||
byte[] bytes = null;
|
||||
String ex = null;
|
||||
try {
|
||||
bytes = Utils.readStreamToEnd(connection.getErrorStream());
|
||||
ex = new String(Utils.readStreamToEnd(new GZIPInputStream(new ByteArrayInputStream(bytes))));
|
||||
} catch (Exception e) {
|
||||
if (bytes != null) {
|
||||
throw new IOException(getBytesAsString(bytes), e);
|
||||
}
|
||||
throw new IOException(connection.getResponseMessage(), e);
|
||||
}
|
||||
throw new IOException(ex);
|
||||
}
|
||||
|
||||
InputStream is = connection.getInputStream();
|
||||
AttestResponse response = new Wire().parseFrom(new GZIPInputStream(is), AttestResponse.class);
|
||||
is.close();
|
||||
return response;
|
||||
}
|
||||
|
||||
private String getBytesAsString(byte[] bytes) {
|
||||
if (bytes == null) return "null";
|
||||
try {
|
||||
CharsetDecoder d = Charset.forName("US-ASCII").newDecoder();
|
||||
CharBuffer r = d.decode(ByteBuffer.wrap(bytes));
|
||||
return r.toString();
|
||||
} catch (Exception e) {
|
||||
return Base64.encodeToString(bytes, Base64.NO_WRAP);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSharedUuid(ISafetyNetCallbacks callbacks) throws RemoteException {
|
||||
PackageUtils.checkPackageUid(context, packageName, getCallingUid());
|
||||
PackageUtils.assertExtendedAccess(context);
|
||||
|
||||
// TODO
|
||||
Log.d(TAG, "dummy Method: getSharedUuid");
|
||||
callbacks.onString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lookupUri(ISafetyNetCallbacks callbacks, String s1, int[] threatTypes, int i, String s2) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: lookupUri");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(ISafetyNetCallbacks callbacks) throws RemoteException {
|
||||
Log.d(TAG, "dummy Method: init");
|
||||
callbacks.onBoolean(Status.SUCCESS, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unknown4(ISafetyNetCallbacks callbacks) throws RemoteException {
|
||||
Log.d(TAG, "dummy Method: unknown4");
|
||||
callbacks.onHarmfulAppsData(Status.SUCCESS, new ArrayList<HarmfulAppsData>());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/snet.proto
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
import okio.ByteString;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.BYTES;
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
|
||||
public final class AttestRequest extends Message {
|
||||
|
||||
public static final ByteString DEFAULT_SAFETYNETDATA = ByteString.EMPTY;
|
||||
public static final String DEFAULT_DROIDGUARDRESULT = "";
|
||||
|
||||
@ProtoField(tag = 1, type = BYTES)
|
||||
public final ByteString safetyNetData;
|
||||
|
||||
@ProtoField(tag = 2, type = STRING)
|
||||
public final String droidGuardResult;
|
||||
|
||||
public AttestRequest(ByteString safetyNetData, String droidGuardResult) {
|
||||
this.safetyNetData = safetyNetData;
|
||||
this.droidGuardResult = droidGuardResult;
|
||||
}
|
||||
|
||||
private AttestRequest(Builder builder) {
|
||||
this(builder.safetyNetData, builder.droidGuardResult);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof AttestRequest)) return false;
|
||||
AttestRequest o = (AttestRequest) other;
|
||||
return equals(safetyNetData, o.safetyNetData)
|
||||
&& equals(droidGuardResult, o.droidGuardResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = safetyNetData != null ? safetyNetData.hashCode() : 0;
|
||||
result = result * 37 + (droidGuardResult != null ? droidGuardResult.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<AttestRequest> {
|
||||
|
||||
public ByteString safetyNetData;
|
||||
public String droidGuardResult;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(AttestRequest message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.safetyNetData = message.safetyNetData;
|
||||
this.droidGuardResult = message.droidGuardResult;
|
||||
}
|
||||
|
||||
public Builder safetyNetData(ByteString safetyNetData) {
|
||||
this.safetyNetData = safetyNetData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder droidGuardResult(String droidGuardResult) {
|
||||
this.droidGuardResult = droidGuardResult;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttestRequest build() {
|
||||
return new AttestRequest(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/snet.proto
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
|
||||
public final class AttestResponse extends Message {
|
||||
|
||||
public static final String DEFAULT_RESULT = "";
|
||||
|
||||
@ProtoField(tag = 2, type = STRING)
|
||||
public final String result;
|
||||
|
||||
public AttestResponse(String result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
private AttestResponse(Builder builder) {
|
||||
this(builder.result);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof AttestResponse)) return false;
|
||||
return equals(result, ((AttestResponse) other).result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
return result != 0 ? result : (hashCode = this.result != null ? this.result.hashCode() : 0);
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<AttestResponse> {
|
||||
|
||||
public String result;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(AttestResponse message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.result = message.result;
|
||||
}
|
||||
|
||||
public Builder result(String result) {
|
||||
this.result = result;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttestResponse build() {
|
||||
return new AttestResponse(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/snet.proto
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
import okio.ByteString;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.BYTES;
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
|
||||
public final class FileState extends Message {
|
||||
|
||||
public static final String DEFAULT_FILENAME = "";
|
||||
public static final ByteString DEFAULT_DIGEST = ByteString.EMPTY;
|
||||
|
||||
@ProtoField(tag = 1, type = STRING)
|
||||
public final String fileName;
|
||||
|
||||
@ProtoField(tag = 2, type = BYTES)
|
||||
public final ByteString digest;
|
||||
|
||||
public FileState(String fileName, ByteString digest) {
|
||||
this.fileName = fileName;
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
private FileState(Builder builder) {
|
||||
this(builder.fileName, builder.digest);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof FileState)) return false;
|
||||
FileState o = (FileState) other;
|
||||
return equals(fileName, o.fileName)
|
||||
&& equals(digest, o.digest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = fileName != null ? fileName.hashCode() : 0;
|
||||
result = result * 37 + (digest != null ? digest.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<FileState> {
|
||||
|
||||
public String fileName;
|
||||
public ByteString digest;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(FileState message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.fileName = message.fileName;
|
||||
this.digest = message.digest;
|
||||
}
|
||||
|
||||
public Builder fileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder digest(ByteString digest) {
|
||||
this.digest = digest;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileState build() {
|
||||
return new FileState(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/snet.proto
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.BOOL;
|
||||
|
||||
public final class SELinuxState extends Message {
|
||||
|
||||
public static final Boolean DEFAULT_SUPPORTED = false;
|
||||
public static final Boolean DEFAULT_ENABLED = false;
|
||||
|
||||
@ProtoField(tag = 1, type = BOOL)
|
||||
public final Boolean supported;
|
||||
|
||||
@ProtoField(tag = 2, type = BOOL)
|
||||
public final Boolean enabled;
|
||||
|
||||
public SELinuxState(Boolean supported, Boolean enabled) {
|
||||
this.supported = supported;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
private SELinuxState(Builder builder) {
|
||||
this(builder.supported, builder.enabled);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof SELinuxState)) return false;
|
||||
SELinuxState o = (SELinuxState) other;
|
||||
return equals(supported, o.supported)
|
||||
&& equals(enabled, o.enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = supported != null ? supported.hashCode() : 0;
|
||||
result = result * 37 + (enabled != null ? enabled.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<SELinuxState> {
|
||||
|
||||
public Boolean supported;
|
||||
public Boolean enabled;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(SELinuxState message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.supported = message.supported;
|
||||
this.enabled = message.enabled;
|
||||
}
|
||||
|
||||
public Builder supported(Boolean supported) {
|
||||
this.supported = supported;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder enabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SELinuxState build() {
|
||||
return new SELinuxState(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/snet.proto
|
||||
package org.microg.gms.snet;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import okio.ByteString;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.BOOL;
|
||||
import static com.squareup.wire.Message.Datatype.BYTES;
|
||||
import static com.squareup.wire.Message.Datatype.INT32;
|
||||
import static com.squareup.wire.Message.Datatype.INT64;
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
import static com.squareup.wire.Message.Label.REPEATED;
|
||||
|
||||
public final class SafetyNetData extends Message {
|
||||
|
||||
public static final ByteString DEFAULT_NONCE = ByteString.EMPTY;
|
||||
public static final String DEFAULT_PACKAGENAME = "";
|
||||
public static final List<ByteString> DEFAULT_SIGNATUREDIGEST = Collections.emptyList();
|
||||
public static final ByteString DEFAULT_FILEDIGEST = ByteString.EMPTY;
|
||||
public static final Integer DEFAULT_GMSVERSIONCODE = 0;
|
||||
public static final List<FileState> DEFAULT_SUCANDIDATES = Collections.emptyList();
|
||||
public static final Long DEFAULT_CURRENTTIMEMS = 0L;
|
||||
public static final Boolean DEFAULT_GOOGLECN = false;
|
||||
|
||||
@ProtoField(tag = 1, type = BYTES)
|
||||
public final ByteString nonce;
|
||||
|
||||
@ProtoField(tag = 2, type = STRING)
|
||||
public final String packageName;
|
||||
|
||||
@ProtoField(tag = 3, type = BYTES, label = REPEATED)
|
||||
public final List<ByteString> signatureDigest;
|
||||
|
||||
@ProtoField(tag = 4, type = BYTES)
|
||||
public final ByteString fileDigest;
|
||||
|
||||
@ProtoField(tag = 5, type = INT32)
|
||||
public final Integer gmsVersionCode;
|
||||
|
||||
@ProtoField(tag = 6, label = REPEATED, messageType = FileState.class)
|
||||
public final List<FileState> suCandidates;
|
||||
|
||||
@ProtoField(tag = 7)
|
||||
public final SELinuxState seLinuxState;
|
||||
|
||||
@ProtoField(tag = 8, type = INT64)
|
||||
public final Long currentTimeMs;
|
||||
|
||||
@ProtoField(tag = 9, type = BOOL)
|
||||
public final Boolean googleCn;
|
||||
|
||||
public SafetyNetData(ByteString nonce, String packageName, List<ByteString> signatureDigest, ByteString fileDigest, Integer gmsVersionCode, List<FileState> suCandidates, SELinuxState seLinuxState, Long currentTimeMs, Boolean googleCn) {
|
||||
this.nonce = nonce;
|
||||
this.packageName = packageName;
|
||||
this.signatureDigest = immutableCopyOf(signatureDigest);
|
||||
this.fileDigest = fileDigest;
|
||||
this.gmsVersionCode = gmsVersionCode;
|
||||
this.suCandidates = immutableCopyOf(suCandidates);
|
||||
this.seLinuxState = seLinuxState;
|
||||
this.currentTimeMs = currentTimeMs;
|
||||
this.googleCn = googleCn;
|
||||
}
|
||||
|
||||
private SafetyNetData(Builder builder) {
|
||||
this(builder.nonce, builder.packageName, builder.signatureDigest, builder.fileDigest, builder.gmsVersionCode, builder.suCandidates, builder.seLinuxState, builder.currentTimeMs, builder.googleCn);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof SafetyNetData)) return false;
|
||||
SafetyNetData o = (SafetyNetData) other;
|
||||
return equals(nonce, o.nonce)
|
||||
&& equals(packageName, o.packageName)
|
||||
&& equals(signatureDigest, o.signatureDigest)
|
||||
&& equals(fileDigest, o.fileDigest)
|
||||
&& equals(gmsVersionCode, o.gmsVersionCode)
|
||||
&& equals(suCandidates, o.suCandidates)
|
||||
&& equals(seLinuxState, o.seLinuxState)
|
||||
&& equals(currentTimeMs, o.currentTimeMs)
|
||||
&& equals(googleCn, o.googleCn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = nonce != null ? nonce.hashCode() : 0;
|
||||
result = result * 37 + (packageName != null ? packageName.hashCode() : 0);
|
||||
result = result * 37 + (signatureDigest != null ? signatureDigest.hashCode() : 1);
|
||||
result = result * 37 + (fileDigest != null ? fileDigest.hashCode() : 0);
|
||||
result = result * 37 + (gmsVersionCode != null ? gmsVersionCode.hashCode() : 0);
|
||||
result = result * 37 + (suCandidates != null ? suCandidates.hashCode() : 1);
|
||||
result = result * 37 + (seLinuxState != null ? seLinuxState.hashCode() : 0);
|
||||
result = result * 37 + (currentTimeMs != null ? currentTimeMs.hashCode() : 0);
|
||||
result = result * 37 + (googleCn != null ? googleCn.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<SafetyNetData> {
|
||||
|
||||
public ByteString nonce;
|
||||
public String packageName;
|
||||
public List<ByteString> signatureDigest;
|
||||
public ByteString fileDigest;
|
||||
public Integer gmsVersionCode;
|
||||
public List<FileState> suCandidates;
|
||||
public SELinuxState seLinuxState;
|
||||
public Long currentTimeMs;
|
||||
public Boolean googleCn;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(SafetyNetData message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.nonce = message.nonce;
|
||||
this.packageName = message.packageName;
|
||||
this.signatureDigest = copyOf(message.signatureDigest);
|
||||
this.fileDigest = message.fileDigest;
|
||||
this.gmsVersionCode = message.gmsVersionCode;
|
||||
this.suCandidates = copyOf(message.suCandidates);
|
||||
this.seLinuxState = message.seLinuxState;
|
||||
this.currentTimeMs = message.currentTimeMs;
|
||||
this.googleCn = message.googleCn;
|
||||
}
|
||||
|
||||
public Builder nonce(ByteString nonce) {
|
||||
this.nonce = nonce;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder packageName(String packageName) {
|
||||
this.packageName = packageName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder signatureDigest(List<ByteString> signatureDigest) {
|
||||
this.signatureDigest = checkForNulls(signatureDigest);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fileDigest(ByteString fileDigest) {
|
||||
this.fileDigest = fileDigest;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder gmsVersionCode(Integer gmsVersionCode) {
|
||||
this.gmsVersionCode = gmsVersionCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder suCandidates(List<FileState> suCandidates) {
|
||||
this.suCandidates = checkForNulls(suCandidates);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder seLinuxState(SELinuxState seLinuxState) {
|
||||
this.seLinuxState = seLinuxState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder currentTimeMs(Long currentTimeMs) {
|
||||
this.currentTimeMs = currentTimeMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder googleCn(Boolean googleCn) {
|
||||
this.googleCn = googleCn;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SafetyNetData build() {
|
||||
return new SafetyNetData(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
option java_package = "org.microg.gms.snet";
|
||||
|
||||
option java_outer_classname = "SafetyNetProto";
|
||||
|
||||
message SELinuxState {
|
||||
optional bool supported = 1;
|
||||
optional bool enabled = 2;
|
||||
}
|
||||
|
||||
message FileState {
|
||||
optional string fileName = 1;
|
||||
optional bytes digest = 2;
|
||||
}
|
||||
|
||||
message SafetyNetData {
|
||||
optional bytes nonce = 1;
|
||||
optional string packageName = 2;
|
||||
repeated bytes signatureDigest = 3;
|
||||
optional bytes fileDigest = 4;
|
||||
optional int32 gmsVersionCode = 5;
|
||||
repeated FileState suCandidates = 6;
|
||||
optional SELinuxState seLinuxState = 7;
|
||||
optional int64 currentTimeMs = 8;
|
||||
optional bool googleCn = 9;
|
||||
}
|
||||
|
||||
message AttestRequest {
|
||||
optional bytes safetyNetData = 1;
|
||||
optional string droidGuardResult = 2;
|
||||
}
|
||||
|
||||
message AttestResponse {
|
||||
optional string result = 2;
|
||||
}
|
Loading…
Reference in New Issue