1 /*
2  * This file was automatically generated by sel-utils and
3  * released under the MIT License.
4  * 
5  * License: https://github.com/sel-project/sel-utils/blob/master/LICENSE
6  * Repository: https://github.com/sel-project/sel-utils
7  * Generated from https://github.com/sel-project/sel-utils/blob/master/xml/protocol/externalconsole2.xml
8  */
9 /**
10  * Packets used during the authentication process and to exhange the initial server's
11  * informations.
12  */
13 module sul.protocol.externalconsole2.login;
14 
15 import std.bitmanip : write, peek;
16 static import std.conv;
17 import std.system : Endian;
18 import std.typetuple : TypeTuple;
19 import std.typecons : Tuple;
20 import std.uuid : UUID;
21 
22 import sul.utils.buffer;
23 import sul.utils.var;
24 
25 static import sul.protocol.externalconsole2.types;
26 
27 static if(__traits(compiles, { import sul.metadata.externalconsole2; })) import sul.metadata.externalconsole2;
28 
29 alias Packets = TypeTuple!(AuthCredentials, Auth, Welcome);
30 
31 /**
32  * First packet sent by the server when the connection is successfully established.
33  * It contains informations about how the external console shall authenticate itself.
34  */
35 class AuthCredentials : Buffer {
36 
37 	public enum ubyte ID = 0;
38 
39 	public enum bool CLIENTBOUND = true;
40 	public enum bool SERVERBOUND = false;
41 
42 	public enum string[] FIELDS = ["protocol", "hash", "hashAlgorithm", "payload"];
43 
44 	/**
45 	 * Protocol used by the server. If the client uses a different one it should close
46 	 * the connection without trying to perform authentication.
47 	 */
48 	public ubyte protocol;
49 
50 	/**
51 	 * Whether to perform hashing on the password or not.
52 	 */
53 	public bool hash;
54 
55 	/**
56 	 * Algorithm used by the server to hash the concatenation of the password and the payload.
57 	 * The value should be sent in lower case without any separation symbol (for example
58 	 * `md5` instead of `MD5`, `sha256` instead of `SHA-256`).
59 	 * See Auth.hash for more details.
60 	 */
61 	public string hashAlgorithm;
62 
63 	/**
64 	 * Payload to cancatenate to the password before hashing it, as described in the Auth.hash's
65 	 * field description.
66 	 */
67 	public ubyte[] payload;
68 
69 	public pure nothrow @safe @nogc this() {}
70 
71 	public pure nothrow @safe @nogc this(ubyte protocol, bool hash=bool.init, string hashAlgorithm=string.init, ubyte[] payload=(ubyte[]).init) {
72 		this.protocol = protocol;
73 		this.hash = hash;
74 		this.hashAlgorithm = hashAlgorithm;
75 		this.payload = payload;
76 	}
77 
78 	public pure nothrow @safe ubyte[] encode(bool writeId=true)() {
79 		_buffer.length = 0;
80 		static if(writeId){ writeBigEndianUbyte(ID); }
81 		writeBigEndianUbyte(protocol);
82 		writeBigEndianBool(hash);
83 		if(hash==true){ writeBigEndianUshort(cast(ushort)hashAlgorithm.length); writeString(hashAlgorithm); }
84 		if(hash==true){ writeBigEndianUshort(cast(ushort)payload.length); writeBytes(payload); }
85 		return _buffer;
86 	}
87 
88 	public pure nothrow @safe void decode(bool readId=true)() {
89 		static if(readId){ ubyte _id; _id=readBigEndianUbyte(); }
90 		protocol=readBigEndianUbyte();
91 		hash=readBigEndianBool();
92 		if(hash==true){ ushort afafz9ar=readBigEndianUshort(); hashAlgorithm=readString(afafz9ar); }
93 		if(hash==true){ payload.length=readBigEndianUshort(); if(_buffer.length>=_index+payload.length){ payload=_buffer[_index.._index+payload.length].dup; _index+=payload.length; } }
94 	}
95 
96 	public static pure nothrow @safe AuthCredentials fromBuffer(bool readId=true)(ubyte[] buffer) {
97 		AuthCredentials ret = new AuthCredentials();
98 		ret._buffer = buffer;
99 		ret.decode!readId();
100 		return ret;
101 	}
102 
103 	public override string toString() {
104 		return "AuthCredentials(protocol: " ~ std.conv.to!string(this.protocol) ~ ", hash: " ~ std.conv.to!string(this.hash) ~ ", hashAlgorithm: " ~ std.conv.to!string(this.hashAlgorithm) ~ ", payload: " ~ std.conv.to!string(this.payload) ~ ")";
105 	}
106 
107 }
108 
109 /**
110  * Performs authentication following the instruncions given by the AuthCredentials
111  * packet.
112  */
113 class Auth : Buffer {
114 
115 	public enum ubyte ID = 1;
116 
117 	public enum bool CLIENTBOUND = false;
118 	public enum bool SERVERBOUND = true;
119 
120 	public enum string[] FIELDS = ["hash"];
121 
122 	/**
123 	 * Pasword encoded as UTF-8 if AuthCredentials.hash is `false` or the hash (specified
124 	 * in AuthCredentials.hashAlgorithm) of the password encoded as UTF-8 concatenated
125 	 * with the bytes from AuthCredentials.payload if `true`.
126 	 * The hash can be done with a function (if hashAlgorithm is `sha1`) in D:
127 	 * ---
128 	 * sha1Of(cast(ubyte[])password ~ authCredentials.payload);
129 	 * ---
130 	 * Or using `MessageDigest` in Java:
131 	 * ---
132 	 * MessageDigest md = MessageDigest.getInstance(authCredentials.hashAlgorithm);
133 	 * md.update(password.getBytes(StandardCharsets.UTF_8));
134 	 * md.update(authCredentials.payload);
135 	 * byte[] hash = md.digest();
136 	 * ---
137 	 */
138 	public ubyte[] hash;
139 
140 	public pure nothrow @safe @nogc this() {}
141 
142 	public pure nothrow @safe @nogc this(ubyte[] hash) {
143 		this.hash = hash;
144 	}
145 
146 	public pure nothrow @safe ubyte[] encode(bool writeId=true)() {
147 		_buffer.length = 0;
148 		static if(writeId){ writeBigEndianUbyte(ID); }
149 		writeBigEndianUshort(cast(ushort)hash.length); writeBytes(hash);
150 		return _buffer;
151 	}
152 
153 	public pure nothrow @safe void decode(bool readId=true)() {
154 		static if(readId){ ubyte _id; _id=readBigEndianUbyte(); }
155 		hash.length=readBigEndianUshort(); if(_buffer.length>=_index+hash.length){ hash=_buffer[_index.._index+hash.length].dup; _index+=hash.length; }
156 	}
157 
158 	public static pure nothrow @safe Auth fromBuffer(bool readId=true)(ubyte[] buffer) {
159 		Auth ret = new Auth();
160 		ret._buffer = buffer;
161 		ret.decode!readId();
162 		return ret;
163 	}
164 
165 	public override string toString() {
166 		return "Auth(hash: " ~ std.conv.to!string(this.hash) ~ ")";
167 	}
168 
169 }
170 
171 /**
172  * Indicates the status of the authentication process.
173  */
174 class Welcome : Buffer {
175 
176 	public enum ubyte ID = 2;
177 
178 	public enum bool CLIENTBOUND = true;
179 	public enum bool SERVERBOUND = false;
180 
181 	public enum string[] FIELDS = ["status"];
182 
183 	public ubyte status;
184 
185 	public pure nothrow @safe @nogc this() {}
186 
187 	public pure nothrow @safe @nogc this(ubyte status) {
188 		this.status = status;
189 	}
190 
191 	public pure nothrow @safe ubyte[] encode(bool writeId=true)() {
192 		_buffer.length = 0;
193 		static if(writeId){ writeBigEndianUbyte(ID); }
194 		writeBigEndianUbyte(status);
195 		return _buffer;
196 	}
197 
198 	public pure nothrow @safe void decode(bool readId=true)() {
199 		static if(readId){ ubyte _id; _id=readBigEndianUbyte(); }
200 		status=readBigEndianUbyte();
201 	}
202 
203 	public static pure nothrow @safe Welcome fromBuffer(bool readId=true)(ubyte[] buffer) {
204 		Welcome ret = new Welcome();
205 		ret._buffer = buffer;
206 		ret.decode!readId();
207 		return ret;
208 	}
209 
210 	public override string toString() {
211 		return "Welcome(status: " ~ std.conv.to!string(this.status) ~ ")";
212 	}
213 
214 	alias _encode = encode;
215 
216 	enum string variantField = "status";
217 
218 	alias Variants = TypeTuple!(Accepted, WrongHash, TimedOut);
219 
220 	/**
221 	 * Sent when the hash sent in Auth matches the server's.
222 	 */
223 	public class Accepted {
224 
225 		public enum typeof(status) STATUS = 0;
226 
227 		public enum string[] FIELDS = ["remoteCommands", "software", "versions", "displayName", "games", "connectedNodes"];
228 
229 		/**
230 		 * Indicates whether the external console can execute command remotely through the
231 		 * Command packet.
232 		 */
233 		public bool remoteCommands;
234 
235 		/**
236 		 * The server's software as a formatted string (without the version).
237 		 */
238 		public string software;
239 
240 		/**
241 		 * Versions of the server in a 3-btyes array readed as `[major, minor, release]`.
242 		 */
243 		public ubyte[3] versions;
244 
245 		/**
246 		 * Name of the server (not the game's MOTD!). It shouldn't contain Minecraft formatting
247 		 * codes.
248 		 */
249 		public string displayName;
250 
251 		/**
252 		 * Informations about the games and their protocols supported by the server.
253 		 */
254 		public sul.protocol.externalconsole2.types.Game[] games;
255 
256 		/**
257 		 * List of names of the nodes connected to the server, if it uses the hub-node layout,
258 		 * or an empty list.
259 		 */
260 		public string[] connectedNodes;
261 
262 		public pure nothrow @safe @nogc this() {}
263 
264 		public pure nothrow @safe @nogc this(bool remoteCommands, string software=string.init, ubyte[3] versions=(ubyte[3]).init, string displayName=string.init, sul.protocol.externalconsole2.types.Game[] games=(sul.protocol.externalconsole2.types.Game[]).init, string[] connectedNodes=(string[]).init) {
265 			this.remoteCommands = remoteCommands;
266 			this.software = software;
267 			this.versions = versions;
268 			this.displayName = displayName;
269 			this.games = games;
270 			this.connectedNodes = connectedNodes;
271 		}
272 
273 		public pure nothrow @safe ubyte[] encode(bool writeId=true)() {
274 			status = 0;
275 			_encode!writeId();
276 			writeBigEndianBool(remoteCommands);
277 			writeBigEndianUshort(cast(ushort)software.length); writeString(software);
278 			writeBytes(versions);
279 			writeBigEndianUshort(cast(ushort)displayName.length); writeString(displayName);
280 			writeBigEndianUshort(cast(ushort)games.length); foreach(zfzm;games){ zfzm.encode(bufferInstance); }
281 			writeBigEndianUshort(cast(ushort)connectedNodes.length); foreach(y9bvdvt9;connectedNodes){ writeBigEndianUshort(cast(ushort)y9bvdvt9.length); writeString(y9bvdvt9); }
282 			return _buffer;
283 		}
284 
285 		public pure nothrow @safe void decode() {
286 			remoteCommands=readBigEndianBool();
287 			ushort c9ddcu=readBigEndianUshort(); software=readString(c9ddcu);
288 			if(_buffer.length>=_index+versions.length){ versions=_buffer[_index.._index+versions.length].dup; _index+=versions.length; }
289 			ushort zlcxe5bu=readBigEndianUshort(); displayName=readString(zlcxe5bu);
290 			games.length=readBigEndianUshort(); foreach(ref zfzm;games){ zfzm.decode(bufferInstance); }
291 			connectedNodes.length=readBigEndianUshort(); foreach(ref y9bvdvt9;connectedNodes){ ushort eldrdk=readBigEndianUshort(); y9bvdvt9=readString(eldrdk); }
292 		}
293 
294 		public override string toString() {
295 			return "Welcome.Accepted(remoteCommands: " ~ std.conv.to!string(this.remoteCommands) ~ ", software: " ~ std.conv.to!string(this.software) ~ ", versions: " ~ std.conv.to!string(this.versions) ~ ", displayName: " ~ std.conv.to!string(this.displayName) ~ ", games: " ~ std.conv.to!string(this.games) ~ ", connectedNodes: " ~ std.conv.to!string(this.connectedNodes) ~ ")";
296 		}
297 
298 	}
299 
300 	/**
301 	 * Sent when Auth is received but the given password or hash doesn't match the server's
302 	 * one.
303 	 */
304 	public class WrongHash {
305 
306 		public enum typeof(status) STATUS = 1;
307 
308 		public enum string[] FIELDS = [];
309 
310 		public pure nothrow @safe ubyte[] encode(bool writeId=true)() {
311 			status = 1;
312 			_encode!writeId();
313 			return _buffer;
314 		}
315 
316 		public pure nothrow @safe void decode() {
317 		}
318 
319 		public override string toString() {
320 			return "Welcome.WrongHash()";
321 		}
322 
323 	}
324 
325 	/**
326 	 * Sent when Auth is not received and the server decides to close the connection because
327 	 * too much time has elapsed since the creation of the socket.
328 	 */
329 	public class TimedOut {
330 
331 		public enum typeof(status) STATUS = 2;
332 
333 		public enum string[] FIELDS = [];
334 
335 		public pure nothrow @safe ubyte[] encode(bool writeId=true)() {
336 			status = 2;
337 			_encode!writeId();
338 			return _buffer;
339 		}
340 
341 		public pure nothrow @safe void decode() {
342 		}
343 
344 		public override string toString() {
345 			return "Welcome.TimedOut()";
346 		}
347 
348 	}
349 
350 }
351