Add decentralized cryptographic identity
This commit is contained in:
parent
0b5b78a553
commit
fa996a6735
27 changed files with 1733 additions and 58 deletions
|
|
@ -1,11 +1,13 @@
|
|||
class_name NetworkProtocol
|
||||
extends RefCounted
|
||||
|
||||
const PROTOCOL_VERSION: int = 2
|
||||
const PROTOCOL_VERSION: int = 3
|
||||
const GAME_BUILD: String = "prealpha"
|
||||
const MAX_DISPLAY_NAME_LENGTH: int = 24
|
||||
const MAX_PROFILE_ID_LENGTH: int = 96
|
||||
const MAX_NONCE_LENGTH: int = 96
|
||||
const MAX_PUBLIC_KEY_LENGTH: int = 8192
|
||||
const MAX_SIGNATURE_LENGTH: int = 2048
|
||||
# ENet channels: 0 reliable lifecycle, 1 movement input, 2 movement
|
||||
# snapshots, 3 fishing input, 4 fishing snapshots, 5 reliable sales,
|
||||
# 6 reliable shop transactions, 7 reliable item/equipment lifecycle,
|
||||
|
|
@ -23,17 +25,56 @@ enum RejectionCode {
|
|||
PROTOCOL_MISMATCH,
|
||||
SERVER_FULL,
|
||||
DUPLICATE_PROFILE,
|
||||
DUPLICATE_IDENTITY,
|
||||
INVALID_IDENTITY_PROOF,
|
||||
AUTHENTICATION_TIMEOUT,
|
||||
SERVER_SHUTTING_DOWN,
|
||||
UNSUPPORTED_CLIENT,
|
||||
}
|
||||
|
||||
|
||||
static func make_identity_hello(
|
||||
public_key: String,
|
||||
fingerprint: String,
|
||||
client_nonce: String,
|
||||
attempt_id: String,
|
||||
) -> Dictionary:
|
||||
return {
|
||||
"protocol_version": PROTOCOL_VERSION,
|
||||
"public_key": public_key,
|
||||
"fingerprint": fingerprint,
|
||||
"client_nonce": client_nonce,
|
||||
"attempt_id": attempt_id,
|
||||
"capability_flags": PackedStringArray(["identity_v1"]),
|
||||
}
|
||||
|
||||
|
||||
static func validate_identity_hello(data: Variant) -> bool:
|
||||
if typeof(data) != TYPE_DICTIONARY:
|
||||
return false
|
||||
var value: Dictionary = data
|
||||
return (
|
||||
typeof(value.get("protocol_version")) == TYPE_INT
|
||||
and typeof(value.get("public_key")) == TYPE_STRING
|
||||
and str(value["public_key"]).to_utf8_buffer().size() <= MAX_PUBLIC_KEY_LENGTH
|
||||
and NetworkIdentityCrypto.valid_fingerprint(value.get("fingerprint"))
|
||||
and typeof(value.get("client_nonce")) == TYPE_STRING
|
||||
and str(value["client_nonce"]).length() == 64
|
||||
and typeof(value.get("attempt_id")) == TYPE_STRING
|
||||
and str(value["attempt_id"]).length() == 32
|
||||
and typeof(value.get("capability_flags")) in [
|
||||
TYPE_ARRAY, TYPE_PACKED_STRING_ARRAY
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
static func make_client_hello(
|
||||
profile_id: String,
|
||||
display_name: String,
|
||||
client_nonce: String,
|
||||
cosmetic_snapshot: Dictionary = {},
|
||||
identity_fingerprint: String = "",
|
||||
identity_signature: PackedByteArray = PackedByteArray(),
|
||||
) -> Dictionary:
|
||||
return {
|
||||
"protocol_version": PROTOCOL_VERSION,
|
||||
|
|
@ -43,6 +84,8 @@ static func make_client_hello(
|
|||
"client_nonce": client_nonce,
|
||||
"capability_flags": PackedStringArray(),
|
||||
"cosmetic_snapshot": cosmetic_snapshot,
|
||||
"identity_fingerprint": identity_fingerprint,
|
||||
"identity_signature": identity_signature,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -58,6 +101,8 @@ static func validate_client_hello(data: Variant) -> String:
|
|||
"client_nonce",
|
||||
"capability_flags",
|
||||
"cosmetic_snapshot",
|
||||
"identity_fingerprint",
|
||||
"identity_signature",
|
||||
]:
|
||||
if not payload.has(key):
|
||||
return "Handshake is missing %s." % key
|
||||
|
|
@ -78,6 +123,13 @@ static func validate_client_hello(data: Variant) -> String:
|
|||
return "Capabilities are invalid."
|
||||
if typeof(payload["cosmetic_snapshot"]) != TYPE_DICTIONARY:
|
||||
return "Cosmetic snapshot is invalid."
|
||||
if (
|
||||
not NetworkIdentityCrypto.valid_fingerprint(
|
||||
payload["identity_fingerprint"]
|
||||
)
|
||||
or typeof(payload["identity_signature"]) != TYPE_PACKED_BYTE_ARRAY
|
||||
):
|
||||
return "Profile identity proof is invalid."
|
||||
var profile_id: String = payload["local_profile_id"]
|
||||
var display_name: String = payload["display_name"]
|
||||
var nonce: String = payload["client_nonce"]
|
||||
|
|
@ -93,6 +145,23 @@ static func validate_client_hello(data: Variant) -> String:
|
|||
return ""
|
||||
|
||||
|
||||
static func client_profile_fields(data: Dictionary) -> Array:
|
||||
var appearance: Dictionary = data.get("cosmetic_snapshot", {})
|
||||
return [
|
||||
str(data.get("client_nonce", "")),
|
||||
str(data.get("identity_fingerprint", "")),
|
||||
str(data.get("local_profile_id", "")),
|
||||
str(data.get("display_name", "")),
|
||||
str(appearance.get("species", "")),
|
||||
str(appearance.get("fur_pattern", "")),
|
||||
str(appearance.get("ears", "")),
|
||||
str(appearance.get("eyes", "")),
|
||||
str(appearance.get("nose", "")),
|
||||
str(appearance.get("mouth", "")),
|
||||
str(appearance.get("tail", "")),
|
||||
]
|
||||
|
||||
|
||||
static func make_server_hello(
|
||||
accepted: bool,
|
||||
rejection_code: RejectionCode,
|
||||
|
|
@ -120,6 +189,7 @@ static func make_server_hello(
|
|||
"chat_v1",
|
||||
"mail_v1",
|
||||
"profile_v1",
|
||||
"identity_v1",
|
||||
]),
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +201,11 @@ static func rejection_text(code: int) -> String:
|
|||
RejectionCode.SERVER_FULL:
|
||||
return "The server is full."
|
||||
RejectionCode.DUPLICATE_PROFILE:
|
||||
return "This local profile is already connected."
|
||||
return "This legacy local profile is already connected."
|
||||
RejectionCode.DUPLICATE_IDENTITY:
|
||||
return "This player identity is already connected."
|
||||
RejectionCode.INVALID_IDENTITY_PROOF:
|
||||
return "Player identity authentication failed."
|
||||
RejectionCode.AUTHENTICATION_TIMEOUT:
|
||||
return "The server did not finish authentication."
|
||||
RejectionCode.SERVER_SHUTTING_DOWN:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue