github.com/Laplace-Game-Development/Laplace-Entangled-Environment@v0.0.3/internal/route/parse.go (about) 1 package route 2 3 import ( 4 "bytes" 5 "encoding/asn1" 6 "encoding/json" 7 "errors" 8 "log" 9 10 "github.com/Laplace-Game-Development/Laplace-Entangled-Environment/internal/data" 11 "github.com/Laplace-Game-Development/Laplace-Entangled-Environment/internal/policy" 12 "github.com/Laplace-Game-Development/Laplace-Entangled-Environment/internal/util" 13 ) 14 15 // commandMap is the mappings of the 2 byte codes to ClientCommands. 16 // predominantly useful in parsing commands for TCP. 17 // 18 // This should never change during runtime! 19 var commandMap map[int64]policy.ClientCmd = map[int64]policy.ClientCmd{ 20 0000 + 0: policy.CmdEmpty, 21 0000 + 1: policy.CmdRegister, 22 0000 + 2: policy.CmdLogin, 23 1<<4 + 0: policy.CmdAction, 24 1<<4 + 1: policy.CmdObserve, 25 1<<8 + 0: policy.CmdGetUser, 26 1<<9 + 0: policy.CmdGameCreate, 27 1<<9 + 1: policy.CmdGameJoin, 28 1<<9 + 2: policy.CmdGameLeave, 29 1<<9 + 3: policy.CmdGameDelete, 30 } 31 32 //// Functions! 33 34 // Parse Command takes a two byte code and returns the associated command 35 // or an error if it doesn't exist. Used mainly in TCP Request Parsing 36 func ParseCommand(mostSignificant byte, leastSignificant byte) (policy.ClientCmd, error) { 37 var cmd int64 = int64(mostSignificant) 38 cmd = (cmd << 8) + int64(leastSignificant) 39 40 log.Printf("Received Command: %d", cmd) 41 42 result, exists := commandMap[cmd] 43 44 if exists == false { 45 return 0, errors.New("Invalid Command") 46 } 47 48 return result, nil 49 } 50 51 // Creates the Authentication Structure based on the structure 52 // and byte slice provided to the function 53 // 54 // isJSON :: whether the byte slice is JSON or ASN1 55 // data :: byte slice of TCP Request Data 56 func parseRequestAttachment(isJSON bool, data *[]byte) (policy.RequestAttachment, int, error) { 57 if isJSON { 58 return decodeJsonAttachment(data) 59 } 60 61 return decodeASN1Attachment(data) 62 } 63 64 // Function for generating structs based on a byte slice. Used to create 65 // RequestBodyFactories. 66 // 67 // ptr should be a pointer to the interface, not the interface itself!!!! 68 // 69 // ptr :: pointer to a struct to populate. Make sure fields are public 70 // (see json.Unmarshall in golang docs) 71 // prefix :: Structure Metadata 72 // body :: byte slice of request data 73 func parseBody(ptr interface{}, prefix TCPRequestPrefix, body *[]byte) error { 74 var err error 75 if prefix.IsBase64Enc { 76 *body, err = util.Base64Decode(body) 77 if err != nil { 78 return err 79 } 80 } 81 82 if prefix.IsJSON { 83 return parseJson(ptr, body) 84 } 85 86 return parseASN1(ptr, body) 87 } 88 89 // General Function for generating responsens and processing request. 90 // Once these fields are populated the request is ready 91 // (see calculateResponse). 92 // 93 // requestHeader :: Common Fields for all requests including authentication and endpoint selection 94 // bodyFactories :: Arguments for the commands in the form of first order functions 95 // isSecured :: Whether the request came over an encrypted connection (i.e. SSL/SSH/HTTPS) 96 // 97 // returns []byte :: byte slice response for user 98 // error :: non-nil when an invalid command is sent or an error occurred when processing 99 // typically means request was rejected. 100 func switchOnCommand(header policy.RequestHeader, bodyFactories policy.RequestBodyFactories, isSecureConnection bool) ([]byte, error) { 101 var res policy.CommandResponse 102 103 if NeedsSecurity(header.Command) && !isSecureConnection { 104 return util.NewErrorJson("Unsecure Connection!"), nil 105 } 106 107 switch header.Command { 108 // Empty Commands 109 case policy.CmdEmpty: 110 res = policy.SuccessfulResponse() 111 break 112 113 // TLS Commands 114 case policy.CmdRegister: 115 res = data.Register(header, bodyFactories, isSecureConnection) 116 break 117 118 case policy.CmdLogin: 119 res = data.Login(header, bodyFactories, isSecureConnection) 120 break 121 122 // cmdStartTLS is an exception to this switch statement. (It occurs in main.go) 123 124 // Through Commands (To Third Party) 125 case policy.CmdAction: 126 res = data.ApplyAction(header, bodyFactories, isSecureConnection) 127 break 128 129 case policy.CmdObserve: 130 res = data.GetGameData(header, bodyFactories, isSecureConnection) 131 break 132 133 // User Management Commands 134 case policy.CmdGetUser: 135 res = data.GetUser(header, bodyFactories, isSecureConnection) 136 break 137 138 // Game Management Commands 139 case policy.CmdGameCreate: 140 res = data.CreateGame(header, bodyFactories, isSecureConnection) 141 break 142 143 case policy.CmdGameJoin: 144 res = data.JoinGame(header, bodyFactories, isSecureConnection) 145 break 146 147 case policy.CmdGameLeave: 148 res = data.LeaveGame(header, bodyFactories, isSecureConnection) 149 break 150 151 default: 152 return nil, errors.New("Command is Not Defined!") 153 } 154 155 if res.ServerError != nil { 156 return nil, res.ServerError 157 } else if res.UseRaw { 158 return res.Raw, nil 159 } 160 161 return res.Digest(res.Data) 162 163 } 164 165 /////////////////////////////////////////////////////////////////////////////////////////////////// 166 //// 167 //// Utility Encoding Functions 168 //// 169 /////////////////////////////////////////////////////////////////////////////////////////////////// 170 171 // Decodes the data byte slice from JSON using policy.RequestAttachment. It 172 // then returns the structure for authentication purposes 173 // 174 // data :: JSON representing a RequestAttachment structure 175 // 176 // returns -> policy.RequestAttachment :: Authentication Data For Requests 177 // int :: index of the rest of the data i.e. args 178 // error :: if parsing goes wrong, error is returned 179 // else it returns nil 180 func decodeJsonAttachment(data *[]byte) (policy.RequestAttachment, int, error) { 181 res := policy.RequestAttachment{} 182 dec := json.NewDecoder(bytes.NewReader(*data)) 183 err := dec.Decode(&res) 184 if err != nil { 185 return res, 0, err 186 } 187 188 return res, int(dec.InputOffset()), nil 189 } 190 191 // Decodes the data byte slice from ASN1 using policy.RequestAttachment. It 192 // then returns the structure for authentication purposes 193 // 194 // data :: ASN1 representing a RequestAttachment structure 195 // 196 // returns -> policy.RequestAttachment :: Authentication Data For Requests 197 // int :: index of the rest of the data i.e. args 198 // error :: if parsing goes wrong, error is returned 199 // else it returns nil 200 func decodeASN1Attachment(data *[]byte) (policy.RequestAttachment, int, error) { 201 res := policy.RequestAttachment{} 202 body, err := asn1.Unmarshal(*data, &res) 203 if err != nil { 204 return res, 0, err 205 } 206 207 bodyStart := len(*data) - len(body) 208 209 return res, bodyStart, nil 210 } 211 212 // Wrapper Function for json.UnMarshall in case we 213 // do our own unmarshalling for any reason 214 func parseJson(ptr interface{}, data *[]byte) error { 215 return json.Unmarshal(*data, ptr) 216 } 217 218 // Wrapper Function for asn1 for unmarshalling for extra 219 // error handling. 220 func parseASN1(ptr interface{}, data *[]byte) error { 221 empty, err := asn1.Unmarshal(*data, ptr) 222 if err != nil { 223 return err 224 } else if len(empty) > 0 { 225 log.Println("ASN1 Parsing Has Extra Bytes... Returning Anyways!") 226 } 227 228 return nil 229 }