Esempio n. 1
0
        public RESTReplyData set_public_key(RESTRequestData pReq, List <string> pArgs)
        {
            RESTReplyData replyData = new RESTReplyData();  // The HTTP response info
            ResponseBody  respBody  = new ResponseBody();

            string includedAPIKey    = null;
            string includedPublicKey = null;
            bool   parsed            = false; // whether multipart was parsed

            try
            {
                // The PUT sends the key as binary but it is later sent around
                //    and processed as a Base64 string.
                Stream byteStream = pReq.RequestBodyMultipartStream("public_key");
                if (byteStream != null)
                {
                    includedPublicKey = Tools.ConvertPublicKeyStreamToBase64(byteStream);
                    // There might has been an APIKey
                    includedAPIKey = pReq.RequestBodyMultipart("api_key");
                    parsed         = true;
                }
                else
                {
                    Context.Log.Error("{0} could not extract public key from request body in PUT user/public_key", _logHeader);
                }
            }
            catch (Exception e)
            {
                Context.Log.Error("{0} exception parsing multi-part http: {1}", _logHeader, e.ToString());
                parsed = false;
            }

            if (parsed)
            {
                // If there is account authorization in the header, set the account public key.
                // If no account authorization (the client is not logged in), check for matching
                //     APIkey and then set the session public key.
                if (String.IsNullOrEmpty(pReq.AuthToken))
                {
                    if (includedAPIKey != null &&
                        Domains.Instance.TryGetDomainWithAPIKey(includedAPIKey, out DomainEntity aDomain))
                    {
                        aDomain.Public_Key = includedPublicKey;
                    }
                    else
                    {
                        Context.Log.Error("{0} PUT user/set_public_key requested without APIKey. APIKey={1}",
                                          _logHeader, includedAPIKey);
                        respBody.RespondFailure("APIkey does not work");
                        replyData.Status = (int)HttpStatusCode.Unauthorized;
                    }
                }
                else
                {
                    if (Accounts.Instance.TryGetAccountWithAuthToken(pReq.AuthToken, out AccountEntity aAccount))
                    {
                        aAccount.Public_Key = includedPublicKey;
                    }
                    else
                    {
                        Context.Log.Error("{0} PUT user/set_public_key requested but could not find acct. Token={1}",
                                          _logHeader, pReq.AuthToken);
                        respBody.RespondFailure("AuthToken unauthorized");
                        replyData.Status = (int)HttpStatusCode.Unauthorized;
                    }
                }
            }
            else
            {
                Context.Log.Error("{0} PUT user/set_public_key failure parsing", _logHeader);
                respBody.RespondFailure("Multi-part body failed parsing");
            }

            replyData.SetBody(respBody, pReq);
            return(replyData);
        }
Esempio n. 2
0
        public RESTReplyData user_create(RESTRequestData pReq, List <string> pArgs)
        {
            RESTReplyData replyData = new RESTReplyData();  // The HTTP response info
            ResponseBody  respBody  = new ResponseBody();   // The request's "data" response info

            if (Sessions.Instance.ShouldBeThrottled(pReq.SenderKey, Sessions.Op.ACCOUNT_CREATE))
            {
                respBody.RespondFailure("Throttled");
                respBody.ErrorData("error", "throttled");
            }
            else
            {
                try
                {
                    bodyUsersPost requestData = pReq.RequestBodyObject <bodyUsersPost>();

                    string userName     = requestData.user["username"];
                    string userPassword = requestData.user["password"];
                    string userEmail    = requestData.user["email"];

                    if (CheckUsernameFormat(userName))
                    {
                        if (CheckEmailFormat(userEmail))
                        {
                            Context.Log.Debug("{0} Creating account {1}/{2}", _logHeader, userName, userEmail);

                            AccountEntity newAcct = Accounts.Instance.CreateAccount(userName, userPassword, userEmail);
                            if (newAcct == null)
                            {
                                respBody.RespondFailure("Username already exists");
                                respBody.ErrorData("username", "already exists");   // legacy HiFi compatibility
                                Context.Log.Debug("{0} Failed acct creation. Username already exists. User={1}",
                                                  _logHeader, userName);
                            }
                            else
                            {
                                // Successful account creation
                                newAcct.IPAddrOfCreator = pReq.SenderKey;
                                newAcct.Updated();
                                Context.Log.Debug("{0} Successful acct creation. User={1}", _logHeader, userName);
                            }
                        }
                        else
                        {
                            respBody.RespondFailure("Bad format for email");
                            respBody.ErrorData("error", "bad format for email");
                        }
                    }
                    else
                    {
                        respBody.RespondFailure("Bad format for username");
                        respBody.ErrorData("error", "bad format for username");
                    }
                }
                catch (Exception e)
                {
                    replyData.Status = (int)HttpStatusCode.BadRequest;
                    Context.Log.Error("{0} Badly formed create account request. {1}", _logHeader, e);
                }
            }

            replyData.SetBody(respBody, pReq);
            return(replyData);
        }
Esempio n. 3
0
        public RESTReplyData user_connections_request_post(RESTRequestData pReq, List <string> pArgs)
        {
            RESTReplyData replyData = new RESTReplyData();  // The HTTP response info
            ResponseBody  respBody  = new ResponseBody();

            if (Accounts.Instance.TryGetAccountWithAuthToken(pReq.AuthToken, out AccountEntity aAccount))
            {
                bodyUserConnectionRequestPost request = pReq.RequestBodyObject <bodyUserConnectionRequestPost>();
                // The script looks for two types of 'connection' responses.
                //    If is sees data.connection == "pending", it trys again and eventually times out
                //    If data.connection has an object, it uses 'new_connection' and 'username'

                // Connection handles are the in-world nodeId's
                string thisNode  = request.user_connection_request.node_id;
                string otherNode = request.user_connection_request.proposed_node_id;

                // BEGIN sanity check DEBUG DEBUG
                {
                    // Connections use node id's to identify the two avatars, I guess because, the
                    //    world does not have access to the account identity.
                    // This debugging code prints out whether the passed nodeIds match the loction
                    //    nodeIds that we have to verify that the connection nodeIds are really the
                    //    same ones as passed in the location.
                    // All this debugging output can go away once nodeId usage is understood.
                    Context.Log.Debug("{0} connection_request: request from account '{1}' node={2}, proposed={3}",
                                      _logHeader, aAccount.Username, thisNode, otherNode);
                    if (aAccount.Location != null)
                    {
                        if (aAccount.Location.NodeID == thisNode)
                        {
                            Context.Log.Debug("{0} connection_request: request from account '{1}' and Location.NodeId matches main node",
                                              _logHeader, aAccount.Username);
                        }
                        else
                        {
                            if (aAccount.Location.NodeID == otherNode)
                            {
                                Context.Log.Debug("{0} connection_request: request from account '{1}' and Location.NodeId matches proposed node",
                                                  _logHeader, aAccount.Username);
                            }
                            else
                            {
                                Context.Log.Debug("{0} connection_request: request from account '{1}' and Location.NodeId does not match either nodes",
                                                  _logHeader, aAccount.Username);
                            }
                        }
                    }
                    else
                    {
                        Context.Log.Debug("{0} connection_request: request from account '{1}' and no location info",
                                          _logHeader, aAccount.Username);
                    }
                }
                // END sanity check DEBUG DEBUG
                try
                {
                    // This returns all the RequestConnection's that have my ID in them
                    RequestConnection previousAsk = RequestConnection.GetNodeRequests(thisNode)
                                                    // Find the ones that have me and the other requestor
                                                    .Where(req =>
                    {
                        return((req.Body.node_id == thisNode && req.Body.proposed_node_id == otherNode) ||
                               (req.Body.node_id == otherNode && req.Body.proposed_node_id == thisNode));
                        // Pick the one (there should be only one)
                    }).FirstOrDefault();

                    if (previousAsk != null)
                    {
                        Context.Log.Debug("{0} connection_request: existing request found", _logHeader);
                        // We have a pending connection request for this person
                        // Mark myself as accepting
                        if (previousAsk.Body.node_id == thisNode)
                        {
                            if (!previousAsk.Body.node_accepted)
                            {
                                previousAsk.Body.node_accepted = true;
                                previousAsk.Updated();
                            }
                        }
                        else
                        {
                            if (!previousAsk.Body.proposed_node_accepted)
                            {
                                previousAsk.Body.proposed_node_accepted = true;
                                previousAsk.Updated();
                            }
                            // I'm in the 'proposed node' position.
                            // Straighten out the node variables for simplier logic after this
                            var tmp = otherNode;
                            otherNode = thisNode;
                            thisNode  = tmp;    // after this, "thisNode" is always this account
                            Context.Log.Debug("{0} connection_request: found request was from other account", _logHeader);
                        }
                        // If both accepted, the connection is complete
                        if (previousAsk.Body.node_accepted && previousAsk.Body.proposed_node_accepted)
                        {
                            if (Accounts.Instance.TryGetAccountWithNodeId(otherNode, out AccountEntity oOtherAccount))
                            {
                                aAccount.AddConnection(oOtherAccount);
                                aAccount.Updated();
                                oOtherAccount.AddConnection(aAccount);
                                oOtherAccount.Updated();
                                respBody.Data = new
                                {
                                    connection = new
                                    {
                                        new_connection = true,      // says whether a new or pre-existing connection
                                        username       = oOtherAccount.Username
                                    }
                                };
                            }
                            else
                            {
                                // Can't find the other account... shouldn't happen
                                respBody.RespondFailure("Both agreed but cannot find other account entity");
                            }
                        }
                        else
                        {
                            // Both haven't accepted so tell the requestor that the request is pending
                            respBody.Data = new Dictionary <string, string>()
                            {
                                { "connection", "pending" }
                            };
                        }
                    }
                    else
                    {
                        // There was no previous ask so create the request.
                        Context.Log.Debug("{0} connection_request: creating connection request from '{1}",
                                          _logHeader, aAccount.Username);
                        RequestConnection newReq = new RequestConnection();
                        newReq.Body.node_id             = thisNode;
                        newReq.Body.requestor_accountId = aAccount.AccountID;
                        newReq.Body.proposed_node_id    = otherNode;
                        newReq.Body.node_accepted       = true;
                        newReq.ExpireIn(TimeSpan.FromSeconds(Context.Params.P <int>(AppParams.P_CONNECTION_REQUEST_SECONDS)));
                        newReq.AddAndUpdate();

                        // Both haven't accepted so tell the requestor that the request is pending
                        respBody.Data = new Dictionary <string, string>()
                        {
                            { "connection", "pending" }
                        };
                    }
                }
                catch
                {
                }
            }
            else
            {
                Context.Log.Error("{0} POST user/connection_request for unauthorized user. Token={1}",
                                  _logHeader, pReq.AuthToken);
                respBody.RespondFailure("Unauthorized");
            }

            replyData.SetBody(respBody, pReq);
            return(replyData);
        }
Esempio n. 4
0
        public RESTReplyData domain_heartbeat(RESTRequestData pReq, List <string> pArgs)
        {
            RESTReplyData replyData = new RESTReplyData();  // The HTTP response info
            ResponseBody  respBody  = new ResponseBody();   // The request's "data" response info

            SessionEntity aSession = Sessions.Instance.UpdateSession(pReq.SenderKey);

            string domainID = pArgs.Count == 1 ? pArgs[0] : null;

            if (Domains.Instance.TryGetDomainWithID(domainID, out DomainEntity aDomain))
            {
                try
                {
                    // Since the body has a lot of optional fields, we need to pick
                    //    through what's sent so we only set what was sent.
                    JObject requestData = pReq.RequestBodyJSON();
                    JObject domainStuff = (JObject)requestData["domain"];
                    string  apiKey      = (string)domainStuff["api_key"];

                    // Context.Log.Debug("{0} domain_heartbeat. Received {1}", _logHeader, pReq.RequestBody);
                    if (VerifyDomainAccess(aDomain, pReq, apiKey, out string oFailureReason))
                    {
                        Tools.SetIfSpecified <string>(domainStuff, "version", ref aDomain.Version);
                        Tools.SetIfSpecified <string>(domainStuff, "protocol", ref aDomain.Protocol);
                        Tools.SetIfSpecified <string>(domainStuff, "network_address", ref aDomain.NetworkAddr);
                        Tools.SetIfSpecified <string>(domainStuff, "automatic_networking", ref aDomain.NetworkingMode);
                        Tools.SetIfSpecified <bool>(domainStuff, "restricted", ref aDomain.Restricted);

                        Tools.SetIfSpecified <int>(domainStuff, "capacity", ref aDomain.Capacity);
                        Tools.SetIfSpecified <string>(domainStuff, "description", ref aDomain.Description);
                        Tools.SetIfSpecified <string>(domainStuff, "maturity", ref aDomain.Maturity);
                        Tools.SetIfSpecified <string>(domainStuff, "restriction", ref aDomain.Restriction);
                        JArray hosts = (JArray)domainStuff["hosts"];
                        if (hosts != null)
                        {
                            aDomain.Hosts = domainStuff["hosts"].ToObject <string[]>();
                        }
                        JArray tags = (JArray)domainStuff["tags"];
                        if (tags != null)
                        {
                            aDomain.Tags = domainStuff["tags"].ToObject <string[]>();
                        }

                        JObject heartbeat = (JObject)domainStuff["heartbeat"];
                        if (heartbeat != null)
                        {
                            Tools.SetIfSpecified <int>(heartbeat, "num_users", ref aDomain.NumUsers);
                            Tools.SetIfSpecified <int>(heartbeat, "num_anon_users", ref aDomain.AnonUsers);
                            aDomain.TotalUsers = aDomain.NumUsers + aDomain.AnonUsers;
                            // TODO: what to do with user_hostnames
                        }

                        aDomain.TimeOfLastHeartbeat = DateTime.UtcNow;
                        aDomain.LastSenderKey       = pReq.SenderKey;

                        aDomain.Updated();
                    }
                    else
                    {
                        Context.Log.Error("{0} domain_heartbeat with bad authorization. domainID={1}",
                                          _logHeader, domainID);
                        respBody.RespondFailure(oFailureReason);
                        replyData.Status = (int)HttpStatusCode.Unauthorized;
                    }
                }
                catch (Exception e)
                {
                    Context.Log.Error("{0} domain_heartbeat: Exception processing body: {1}", _logHeader, e.ToString());
                    respBody.RespondFailure("exception processing body", e.ToString());
                    replyData.Status = (int)HttpStatusCode.BadRequest;
                }
            }
            else
            {
                Context.Log.Error("{0} domain_heartbeat: unknown domain. Returning 404", _logHeader);
                respBody.RespondFailure("no such domain");
                replyData.Status = (int)HttpStatusCode.NotFound; // this will trigger a new temporary domain name
            }

            replyData.SetBody(respBody, pReq);
            return(replyData);
        }