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  }