package peergos.shared.user.fs;
import jsinterop.annotations.*;
import peergos.shared.cbor.*;
import peergos.shared.crypto.*;
import peergos.shared.crypto.asymmetric.*;
import peergos.shared.crypto.symmetric.SymmetricKey;
import peergos.shared.io.ipfs.multibase.*;
import peergos.shared.util.*;
import java.util.*;
public class FilePointer implements Cborable {
public final Location location;
public final SymmetricKey baseKey;
public final Optional<SecretSigningKey> writer;
@JsConstructor
public FilePointer(Location location, Optional<SecretSigningKey> writer, SymmetricKey baseKey) {
this.location = location;
this.baseKey = baseKey;
this.writer = writer;
}
public FilePointer(PublicSigningKey owner, PublicSigningKey writer, byte[] mapKey, SymmetricKey baseKey) {
this(new Location(owner, writer, mapKey), Optional.empty(), baseKey);
}
public FilePointer(PublicSigningKey owner, SigningKeyPair writer, byte[] mapKey, SymmetricKey baseKey) {
this(new Location(owner, writer.publicSigningKey, mapKey), Optional.of(writer.secretSigningKey), baseKey);
}
public Location getLocation() {
return location;
}
public SigningKeyPair signer() {
if (! writer.isPresent())
throw new IllegalStateException("Can't get signer for a read only pointer!");
return new SigningKeyPair(location.writer, writer.get());
}
public FilePointer withBaseKey(SymmetricKey newBaseKey) {
return new FilePointer(location, writer, newBaseKey);
}
public FilePointer withWritingKey(PublicSigningKey writingKey) {
return new FilePointer(location.withWriter(writingKey), Optional.empty(), baseKey);
}
@Override
public CborObject toCbor() {
Map<String, CborObject> cbor = new TreeMap<>();
cbor.put("l", location.toCbor());
cbor.put("k", baseKey.toCbor());
writer.ifPresent(secret -> cbor.put("s", secret.toCbor()));
return CborObject.CborMap.build(cbor);
}
public static FilePointer fromByteArray(byte[] raw) {
return fromCbor(CborObject.fromByteArray(raw));
}
public static FilePointer fromCbor(CborObject cbor) {
if (! (cbor instanceof CborObject.CborMap))
throw new IllegalStateException("Incorrect cbor for FilePointer: " + cbor);
SortedMap<CborObject, CborObject> map = ((CborObject.CborMap) cbor).values;
Location loc = Location.fromCbor(map.get(new CborObject.CborString("l")));
SymmetricKey baseKey = SymmetricKey.fromCbor(map.get(new CborObject.CborString("k")));
CborObject.CborString secretLabel = new CborObject.CborString("s");
Optional<SecretSigningKey> writer = map.containsKey(secretLabel) ? Optional.of(SecretSigningKey.fromCbor(map.get(secretLabel))) : Optional.empty();
return new FilePointer(loc, writer, baseKey);
}
public FilePointer readOnly() {
if (!isWritable())
return this;
return new FilePointer(this.location, Optional.empty(), this.baseKey);
}
public boolean isWritable() {
return writer.isPresent();
}
public String toLink() {
return "#" + Base58.encode(location.writer.serialize()) + "/" + Base58.encode(location.getMapKey()) + "/" + Base58.encode(baseKey.serialize());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilePointer that = (FilePointer) o;
if (location != null ? !location.equals(that.location) : that.location != null) return false;
return baseKey != null ? baseKey.equals(that.baseKey) : that.baseKey == null;
}
@Override
public int hashCode() {
int result = location != null ? location.hashCode() : 0;
result = 31 * result + (baseKey != null ? baseKey.hashCode() : 0);
return result;
}
@Override
public String toString() {
return ArrayOps.bytesToHex(location.getMapKey());
}
public boolean isNull() {
PublicSigningKey nullUser = PublicSigningKey.createNull();
return nullUser.equals(location.owner) &&
nullUser.equals(location.writer) &&
Arrays.equals(location.getMapKey(), new byte[32]) &&
baseKey.equals(SymmetricKey.createNull());
}
public static FilePointer fromLink(String keysString) {
if (keysString.startsWith("#"))
keysString = keysString.substring(1);
String[] split = keysString.split("/");
PublicSigningKey owner = PublicSigningKey.createNull();
PublicSigningKey writer = PublicSigningKey.fromByteArray(Base58.decode(split[0]));
byte[] mapKey = Base58.decode(split[1]);
SymmetricKey baseKey = SymmetricKey.fromByteArray(Base58.decode(split[2]));
return new FilePointer(owner, writer, mapKey, baseKey);
}
public static FilePointer createNull() {
return new FilePointer(PublicSigningKey.createNull(), PublicSigningKey.createNull(), new byte[32], SymmetricKey.createNull());
}
}