forked from team-sg/hero-mark-2
basic newgrounds.io network protocol support
This commit is contained in:
parent
cf5064f9eb
commit
92b4dbe5a8
3 changed files with 126 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
.import/
|
||||
build/
|
||||
build/
|
||||
ngio.ini
|
123
autoloads/ngio.gd
Normal file
123
autoloads/ngio.gd
Normal file
|
@ -0,0 +1,123 @@
|
|||
extends Node
|
||||
|
||||
|
||||
const GATEWAY_URI: String = "https://newgrounds.io/gateway_v3.php"
|
||||
|
||||
|
||||
var app_id: String = "" # app id on newgrounds
|
||||
var aes_key := PoolByteArray([]) # AES-128/Base64 encryption key
|
||||
var keys_loaded: bool = false # whether id and key have been loaded from ini file
|
||||
|
||||
var http := HTTPRequest.new() # http request node
|
||||
var aes := AESContext.new() # aes encryption
|
||||
var rng := RandomNumberGenerator.new()
|
||||
|
||||
|
||||
var _response: Dictionary = {}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# load app id from ngio.ini
|
||||
var ini = ConfigFile.new()
|
||||
var err = ini.load("res://ngio.ini")
|
||||
if err != OK:
|
||||
push_error("Failed to load ngio data. Will not be able to access scoreboards.")
|
||||
return
|
||||
app_id = ini.get_value("ngio", "id", "")
|
||||
if app_id == "":
|
||||
push_error("Failed to load ngio data. Will not be able to access scoreboards.")
|
||||
keys_loaded = false
|
||||
else:
|
||||
keys_loaded = true
|
||||
|
||||
# attempt to load aes key
|
||||
var key = Marshalls.base64_to_raw(ini.get_value("ngio", "key", ""))
|
||||
if key.size() == 16:
|
||||
aes_key = key
|
||||
|
||||
# initialize HTTPRequest
|
||||
add_child(http)
|
||||
http.connect("request_completed", self, "_http_request_completed")
|
||||
|
||||
# initialize rng for encryption
|
||||
rng.randomize()
|
||||
|
||||
|
||||
func _test_http() -> void:
|
||||
print(yield(request_execute("Gateway.getDatetime"), "completed"))
|
||||
print(yield(request_execute(["Gateway.getDatetime", "Gateway.getVersion"], {}, "", ["blep", "bleepo"]), "completed"))
|
||||
|
||||
|
||||
## requests the provided component be executed, do not call async :/
|
||||
# may call with either single or multiple components
|
||||
func request_execute(component, parameters = {}, session_id: String = "", echo = null, encrypt: bool = false) -> Dictionary:
|
||||
# build request headers
|
||||
var headers = [
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
]
|
||||
# build execute object
|
||||
var execute
|
||||
if component is Array:
|
||||
execute = []
|
||||
for i in component.size():
|
||||
if component[i] is String:
|
||||
execute.append({
|
||||
component = component[i],
|
||||
})
|
||||
if parameters is Array and parameters[i] is Dictionary:
|
||||
execute[-1].parameters = parameters[i]
|
||||
if echo is Array and echo[i] is String:
|
||||
execute[-1].echo = echo[i]
|
||||
else:
|
||||
execute = {
|
||||
component = component,
|
||||
parameters = parameters,
|
||||
}
|
||||
if echo is String:
|
||||
execute.echo = echo
|
||||
# use encryption if a valid key is available
|
||||
# TODO: implementation messed up in some way. encryption is fine, but
|
||||
# formatting is wrong in some way that newgrounds can not understand
|
||||
# if encrypt and aes_key.size() == 16:
|
||||
if false:
|
||||
# convert to bytes
|
||||
var data = to_json(execute).to_utf8()
|
||||
# pad to 16 bytes alignment
|
||||
var padding = PoolByteArray([])
|
||||
padding.resize((16 - data.size() % 16) % 16)
|
||||
padding.fill(0)
|
||||
data.append_array(padding)
|
||||
# generate random initialization vector
|
||||
var iv = PoolByteArray([])
|
||||
iv.resize(16)
|
||||
for i in iv.size():
|
||||
iv[i] = rng.randi() % 0xFF
|
||||
# encrypt data
|
||||
aes.start(AESContext.MODE_CBC_ENCRYPT, aes_key, iv)
|
||||
var encrypted = aes.update(data)
|
||||
aes.finish()
|
||||
# compose secure execute object
|
||||
execute = {
|
||||
secure = Marshalls.raw_to_base64(iv + encrypted)
|
||||
}
|
||||
# compose request body
|
||||
var request = {
|
||||
app_id = app_id,
|
||||
session_id = session_id,
|
||||
execute = execute,
|
||||
}
|
||||
var body = "input=" + to_json(request).percent_encode()
|
||||
# make request
|
||||
var err = http.request(GATEWAY_URI, headers, true, HTTPClient.METHOD_POST, body)
|
||||
# yield response
|
||||
yield(http, "request_completed")
|
||||
return _response
|
||||
|
||||
## called when the HTTPRequest gets a responce
|
||||
func _http_request_completed(result: int, response_code: int, headers: PoolStringArray, body: PoolByteArray) -> void:
|
||||
if response_code == 200:
|
||||
var dict = parse_json(body.get_string_from_utf8())
|
||||
if typeof(dict) == TYPE_DICTIONARY:
|
||||
_response = dict
|
||||
return
|
||||
_response = {success = false}
|
|
@ -82,6 +82,7 @@ SceneManager="*res://autoloads/scene_manager.tscn"
|
|||
Console="*res://autoloads/console.tscn"
|
||||
Fade="*res://autoloads/fade.tscn"
|
||||
StainLayer="*res://autoloads/stain_layer.tscn"
|
||||
Ngio="*res://autoloads/ngio.gd"
|
||||
|
||||
[debug]
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue