/// <summary>Runs this API with the given JSON payload and a signee.</summary> public override JSObject Run(JSObject payload, Signee signer, Location at) { // First we need to build a JWS if we have a payload. if (payload != null) { // Build the JWS. // It has no header and no protected header because: // - The header originates from the signer // (i.e. it adds the 'entity', 'pk' or 'device' field to the header) // - Protected header is only ever used by root nodes forwarding to other root nodes. payload = JWS.Build(null, null, payload, signer); } // Now perform the HTTP request (get/post depending on if we have a payload or not). HttpResponse req; JSObject result = Http.Request(FullPath(at), payload, out req); if (!req.Ok) { // It errored! Result is either null or an error description. throw new Exception("API Errored! " + (result != null)); } // Has it got a Sequence header? string seq = req.Sequence; if (seq != null && signer != null) { // Yes - update the signer: signer.Sequence = seq; } return(result); }
/// <summary>Runs the given function at this location.</summary> public JSObject Run(string function, JSObject payload, Signee signer) { // Get the function from the API: ApiObject func = Api[function]; if (func == null) { // Function not found. throw new Exception("The function '" + function + "' is not a valid function for this API."); } // Try running it: return(func.Run(payload, signer, this)); }
/// <summary>Runs this API with the given JSON payload and a signee.</summary> public virtual JSObject Run(JSObject payload, Signee signer, Location at) { // This occurs when the user, for example, attempted to 'run' an API type. // An example of a type is error/field/invalid - an error object description. throw new Exception("This only works on Api functions."); }
/// <summary>Builds a JWS from JSON objects.</summary> public static JSObject Build(JSObject header, JSObject pHeader, JSObject payload, Signee signer) { // Get the time in ms: ulong timeMS = Time.UnixTimeMs; // Generate an ID: string id = RandomString.Hex(20) + "@" + timeMS; // Sign the ID. This is the public signature which will appear in the public change log: string pubSig64 = signer.Sign(id); if (header == null) { // The header is almost always null; create a new one: header = new JSArray(); } if (pHeader == null) { // The protected header is almost always null; create a new one: pHeader = new JSArray(); } // Ask the signer to populate the JWS header - for example, putting the entity endpoint in there: signer.GetJwsHeader(header); // Add the pubsig, ID and sequence code to our protected header: pHeader["id"] = new JSValue(id); pHeader["pubsig"] = new JSValue(pubSig64); if (!string.IsNullOrEmpty(signer.Sequence)) { // Apply the sequence code: pHeader["seq"] = new JSValue(signer.Sequence); } // Base64 both strings: string payload64 = Base64.Encode(JSON.Stringify(payload)); string pHeader64 = Base64.Encode(JSON.Stringify(pHeader)); if (payload64 == "e30=") { // Strip the {} case (doesn't happen with the protected header). payload64 = ""; } // Sign the base64 strings combined with a .: string signature64 = signer.Sign(pHeader64 + "." + payload64); // Build the JWS itself: JSArray jws = new JSArray(); // Add the values: jws["header"] = header; jws["payload"] = new JSValue(payload64); jws["protected"] = new JSValue(pHeader64); jws["signature"] = new JSValue(signature64); return(jws); }