Example #1
0
        void KPRPCReceiveJSONRPC(JSONRPCContainer jsonrpcEncrypted, KeePassRPCService service)
        {
            string        jsonrpc = Decrypt(jsonrpcEncrypted);
            StringBuilder sb      = new StringBuilder();

            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(service);

            dispatcher.Process(new StringReader(jsonrpc),
                               new StringWriter(sb), Authorised);
            string output = sb.ToString();

            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol = "jsonrpc";
            data2client.version  = ProtocolVersion;
            data2client.jsonrpc  = Encrypt(output);

            // If there was a problem encrypting our message, respond to the
            // client with a non-encrypted error message
            if (data2client.jsonrpc == null)
            {
                data2client          = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.version  = ProtocolVersion;
                data2client.error    = new Error(ErrorCode.AUTH_RESTART, new string[] { "Encryption error" });
                this.Authorised      = false;
                if (KPRPC.logger != null)
                {
                    KPRPC.logger.WriteLine("Encryption error when trying to reply to client message");
                }
            }
            _webSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
        }
Example #2
0
        protected override void ProcessRequest()
        {
            if (!CaselessString.Equals(Request.RequestType, "POST"))
            {
                throw new JsonRpcException(string.Format("HTTP {0} is not supported for RPC execution. Use HTTP POST only.", Request.RequestType));
            }

            //
            // Sets the "Cache-Control" header value to "no-cache".
            // NOTE: It does not send the common HTTP 1.0 request directive
            // "Pragma" with the value "no-cache".
            //

            Response.Cache.SetCacheability(HttpCacheability.NoCache);

            //
            // Response will be plain text, though it would have been nice to
            // be more specific, like text/json.
            //

            Response.ContentType = "application/json";

            //
            // Delegate rest of the work to JsonRpcServer.
            //

            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(Service);

            using (new JsonRpcDispatchScope(dispatcher, Context))
                using (TextReader reader = GetRequestReader())
                    dispatcher.Process(reader, Response.Output);
        }
Example #3
0
        public void HandleConnection(TcpClient tcp)
        {
            var ns = tcp.GetStream();

            using (var sw = new StreamWriter(ns)
            {
                AutoFlush = true
            })
                using (var sr = new StreamReader(ns))
                {
                    LogMessage(string.Format("Incoming connection from {0}", tcp.Client.RemoteEndPoint.ToString()));
                    JsonRpcDispatcherFactory.CreateDispatcher(Handler).Process(sr, sw);
                    LogMessage("Closed connection");
                }
        }
Example #4
0
        protected override void ProcessRequest()
        {
            string httpMethod = Request.RequestType;

            if (!CaselessString.Equals(httpMethod, "GET") &&
                !CaselessString.Equals(httpMethod, "HEAD"))
            {
                throw new JsonRpcException(string.Format("HTTP {0} is not supported for RPC execution. Use HTTP GET or HEAD only.", httpMethod));
            }

            string callback = Mask.NullString(Request.QueryString["jsonp"]);
            bool   padded   = callback.Length > 0;

            //
            // The response type depends on whether JSONP (JSON with
            // Padding) is in effect or not.
            //

            Response.ContentType = padded ? "text/javascript" : "application/json";

            //
            // Validate that the JSONP callback method conforms to the
            // allowed syntax. If not, issue a client-side exception
            // that will certainly help to bring problem to light, even if
            // a little too aggressively.
            //

            if (padded)
            {
                if (!_jsonpex.IsMatch(callback))
                {
                    Response.Write("throw new Error('Invalid JSONP callback parameter value.');");
                    Response.End();
                }
            }

            //
            // Convert the query string into a call object.
            //

            StringWriter sw     = new StringWriter();
            JsonWriter   writer = JsonText.CreateWriter(sw);

            writer.WriteStartObject();

            writer.WriteMember("id");
            writer.WriteNumber(-1);

            writer.WriteMember("method");

            string methodName = Mask.NullString(Request.PathInfo);

            if (methodName.Length == 0)
            {
                writer.WriteNull();
            }
            else
            {
                //
                // If the method name contains periods then we replace it
                // with dashes to mean the one and same thing. This is
                // done to provide dashes as an alternative to some periods
                // since some web servers may block requests (for security
                // reasons) if a path component of the URL contains more
                // than one period.
                //

                writer.WriteString(methodName.Substring(1).Replace('-', '.'));
            }

            writer.WriteMember("params");
            NameValueCollection query = new NameValueCollection(Request.QueryString);

            query.Remove(string.Empty);
            JsonConvert.Export(Request.QueryString, writer);

            writer.WriteEndObject();

            //
            // Delegate rest of the work to JsonRpcDispatcher.
            //

            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(Service);

            using (new JsonRpcDispatchScope(dispatcher, Context))
            {
                dispatcher.RequireIdempotency = true;

                if (padded)
                {
                    //
                    // For JSONP, see details here:
                    // http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/
                    //

                    Response.Write(callback);
                    Response.Write('(');
                }

                dispatcher.Process(new StringReader(sw.ToString()), Response.Output, true);

                if (padded)
                {
                    Response.Write(')');
                }
            }
        }
Example #5
0
        /// <summary>
        /// Does some basic authentication checks and then
        /// dispatches to the JayRock RPC system.
        /// </summary>
        /// <param name="message">The JSON-RPC formatted message.</param>
        /// <param name="keePassRPCClient">The client we're communicating with.</param>
        private void DispatchToRPCService(string message, KeePassRPCClientConnection keePassRPCClientConnection)
        {
            if (KeePassRPCPlugin.logger != null)
            {
                KeePassRPCPlugin.logger.WriteLine("Preparing to dispatch: " + message);
            }
            StringBuilder sb = new StringBuilder();
            string        requiredResultRegex    = "";
            long          authorisationAttemptId = -1;

            if (!keePassRPCClientConnection.Authorised && _authorisationRequired)
            {
                Match match = Regex.Match(message,
                                          "^\\{.*?\\\"method\\\"\\:\\\"Idle\\\".*?,.*?\\\"id\\\"\\:(\\d+).*?\\}$");
                if (match.Success)
                {
                    if (KeePassRPCPlugin.logger != null)
                    {
                        KeePassRPCPlugin.logger.WriteLine("Got Idle method- ignoring.");
                    }
                    // Do nothing
                    return;
                }
                else   // Check for alternative Idle message structure
                {
                    match = Regex.Match(message,
                                        "^\\{.*?\\\"id\\\"\\:(\\d+).*?,.*?\\\"method\\\"\\:\\\"Idle\\\".*?\\}$");
                    if (match.Success)
                    {
                        if (KeePassRPCPlugin.logger != null)
                        {
                            KeePassRPCPlugin.logger.WriteLine("Got Idle method- ignoring.");
                        }
                        // Do nothing
                        return;
                    }
                }
            }

            if (!keePassRPCClientConnection.Authorised && _authorisationRequired)
            {
                // We only accept one type of request if the client has not
                // already authenticated. Maybe it's not nice having to do this
                // outside of the main JayRockJsonRpc library but it'll be good enough

                Match match = Regex.Match(message,
                                          "^\\{.*?\\\"method\\\"\\:\\\"Authenticate\\\".*?,.*?\\\"id\\\"\\:(\\d+).*?\\}$");
                if (!match.Success)
                {
                    match = Regex.Match(message,
                                        "^\\{.*?\\\"id\\\"\\:(\\d+).*?,.*?\\\"method\\\"\\:\\\"Authenticate\\\".*?\\}$");
                    if (!match.Success)
                    {
                        throw new AuthorisationException("Authentication required. You must send a properly formed JSON Authenticate request before using this connection.", -1, 1);
                    }
                }

                authorisationAttemptId = int.Parse(match.Groups[1].Value);
                requiredResultRegex    = "^\\{\\\"id\\\"\\:" + authorisationAttemptId + ",\\\"result\\\"\\:\\{\\\"result\\\"\\:0,\\\"name\\\"\\:\\\"(.*)\\\"\\}\\}$";
            }

            //Stream clientStream = keePassRPCClientConnection.ConnectionStream;

            //TODO2: is this Jayrock stuff thread-safe or do I need new instances of the Service each time?
            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(Service);

            dispatcher.Process(new StringReader(message),
                               new StringWriter(sb), keePassRPCClientConnection.Authorised);
            string output = sb.ToString();

            //MessageBox.Show("result: " + output);
            if (_authorisationRequired && !keePassRPCClientConnection.Authorised)
            {
                string authenticatedClientName;

                // Process the output from the JsonRpcDispatcher which
                // should tell us if the authorisation was successful
                Match match = Regex.Match(output, requiredResultRegex);
                if (match.Success)
                {
                    authenticatedClientName = match.Groups[1].Value;
                    keePassRPCClientConnection.Authorised = true;
                    KeePassRPCPlugin.PromoteNullRPCClient(keePassRPCClientConnection, authenticatedClientName);
                }
                else
                {
                    // If the result follows an accepted syntax we will send
                    // it back to the client so they know why it failed but otherwise...
                    if (!Regex.IsMatch(output,
                                       "^\\{\\\"id\\\"\\:(\\d+),\\\"result\\\"\\:\\{\\\"result\\\"\\:(\\d+),\\\"name\\\"\\:\\\".*\\\"\\}\\}$"))
                    {
                        MessageBox.Show("ERROR! Please click on this box, press CTRL-C on your keyboard and paste into a new post on the KeeFox forum (http://keefox.org/help/forum). Doing this will help other people to use KeeFox without any unexpected error messages like this. Please briefly describe what you were doing when the problem occurred, which version of KeeFox, KeePass and Firefox you use and what other security software you run on your machine. Thanks! Technical detail follows: " + output);
                        return; // maybe could return a proper result indicating failure
                        //but user might get annoyed with this popup appearing every 10 seconds!
                    }
                }
            }

            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(output);
            keePassRPCClientConnection.ConnectionStreamWrite(bytes);
        }