Пример #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));
        }
Пример #2
0
        public void ReceiveMessage(string message, KeePassRPCService service)
        {
            // Inspect incoming message
            KPRPCMessage kprpcm;

            try
            {
                kprpcm = (KPRPCMessage)Jayrock.Json.Conversion.JsonConvert.Import(typeof(KPRPCMessage), message);
            }
            catch (Exception)
            {
                kprpcm = null;
            }

            if (kprpcm == null)
            {
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.INVALID_MESSAGE, new string[] { "Contents can't be interpreted as an SRPEncapsulatedMessage" });

                AbortWithMessageToClient(data2client);
                return;
            }

            if (kprpcm.version != ProtocolVersion)
            {
                if (!ClientSupportsRequiredFeatures(kprpcm.features))
                {
                    RejectClientVersion(kprpcm);
                    return;
                }
            }

            switch (kprpcm.protocol)
            {
            case "setup": KPRPCReceiveSetup(kprpcm); break;

            case "jsonrpc": KPRPCReceiveJSONRPC(kprpcm.jsonrpc, service); break;

            default: KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.UNRECOGNISED_PROTOCOL, new string[] { "Use setup or jsonrpc" });

                AbortWithMessageToClient(data2client);
                return;
            }
        }
Пример #3
0
        public MatchAccuracyEnum CalculatesCorrectMatchAccuracyScore(string urlEntry, string urlSearch, MatchAccuracyMethod entryMam)
        {
            var pwe = new PwEntry(true, true);

            pwe.Strings.Set("URL", new ProtectedString(false, urlEntry));
            var conf = new EntryConfig(entryMam);

            pwe.SetKPRPCConfig(conf);
            var urlSummary = URLSummary.FromURL(urlSearch);

            return((MatchAccuracyEnum)KeePassRPCService.BestMatchAccuracyForAnyURL(pwe, conf, urlSearch, urlSummary, entryMam));
        }
Пример #4
0
 /// <summary>
 /// Starts the web socket listener
 /// </summary>
 /// <param name="service">The KeePassRPCService the server should interact with.</param>
 public KeePassRPCServer(KeePassRPCService service, KeePassRPCExt keePassRPCPlugin, int webSocketPort, bool bindOnlyToLoopback)
 {
     if (keePassRPCPlugin.logger != null)
     {
         keePassRPCPlugin.logger.WriteLine("Starting KPRPCServer");
     }
     Service          = service;
     KeePassRPCPlugin = keePassRPCPlugin;
     StartWebsockServer(webSocketPort, bindOnlyToLoopback);
     if (keePassRPCPlugin.logger != null)
     {
         keePassRPCPlugin.logger.WriteLine("Started KPRPCServer");
     }
 }
Пример #5
0
 /// <summary>
 /// Starts the web socket listener
 /// </summary>
 /// <param name="service">The KeePassRPCService the server should interact with.</param>
 public KeePassRPCServer(KeePassRPCService service, KeePassRPCExt keePassRPCPlugin, WebSocketServerConfig websocketConfig)
 {
     if (keePassRPCPlugin.logger != null)
     {
         keePassRPCPlugin.logger.WriteLine("Starting KPRPCServer");
     }
     Service          = service;
     KeePassRPCPlugin = keePassRPCPlugin;
     WebsocketConfig  = websocketConfig;
     StartWebsockServer(websocketConfig);
     if (keePassRPCPlugin.logger != null)
     {
         keePassRPCPlugin.logger.WriteLine("Started KPRPCServer");
     }
 }
Пример #6
0
        public void ReceiveMessage(string message, KeePassRPCService service)
        {
            // Inspect incoming message
            KPRPCMessage kprpcm;
            int          requiredCommsVersion = 1;

            try
            {
                kprpcm = (KPRPCMessage)Jayrock.Json.Conversion.JsonConvert.Import(typeof(KPRPCMessage), message);
            }
            catch (Exception)
            {
                kprpcm = null;
            }

            if (kprpcm == null)
            {
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.INVALID_MESSAGE, new string[] { "Contents can't be interpreted as an SRPEncapsulatedMessage" });
                this.Authorised   = false;

                string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
                this.WebSocketConnection.Send(response);
                return;
            }

            if (kprpcm.version != ProtocolVersion)
            {
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(kprpcm.version > ProtocolVersion ? ErrorCode.VERSION_CLIENT_TOO_HIGH : ErrorCode.VERSION_CLIENT_TOO_LOW, new string[] { ProtocolVersion.ToString() });
                this.Authorised   = false;

                string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
                this.WebSocketConnection.Send(response);
                return;
            }

            //1: Is it an SRP message?
            switch (kprpcm.protocol)
            {
            case "setup": KPRPCReceiveSetup(kprpcm); break;

            case "jsonrpc": KPRPCReceiveJSONRPC(kprpcm.jsonrpc, service); break;

            default: KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.UNRECOGNISED_PROTOCOL, new string[] { "Use setup or jsonrpc" });
                this.Authorised   = false;

                string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
                this.WebSocketConnection.Send(response);
                return;
            }
        }
Пример #7
0
        /// <summary>
        /// The <c>Initialize</c> function is called by KeePass when
        /// you should initialize your plugin (create menu items, etc.).
        /// </summary>
        /// <param name="host">Plugin host interface. By using this
        /// interface, you can access the KeePass main window and the
        /// currently opened database.</param>
        /// <returns>true if channel registered correctly, otherwise false</returns>
        public override bool Initialize(IPluginHost host)
        {
            try
            {
                Debug.Assert(host != null);
                if (host == null)
                {
                    return(false);
                }
                _host = host;

                // Reduce Fleck library logging verbosity
                Fleck2.FleckLog.Level = Fleck2.LogLevel.Error;

                // Enable update checks
                KeePass.Util.UpdateCheckEx.SetFileSigKey(UpdateUrl, "<RSAKeyValue><Modulus>t2jki5ttRkT7D110Q5n/ZdgFZ7JGdlRDme0NvcG1Uz7CnGF40NOqWtuzW4a9p0xUN05I5JegaJ20Nu6ejuxMfOhn0jUALHYe6F2wn4yGbPHJvXLXYyc3fU7W75eWJwQabup2vKhrAjvPMSQfy05JgPcfDmLk0txuKkrPO0u3d9ZzZsYrW+GLyJAQAT9Lt87A04iQsPxB30gXv4JX7iOqtKVsWfKEzanX/zuA5XB8JEd2I7bh2u0AgUA2rnwjSkI01tb6BheruwWm5GLZhe+k/wQkgiTxLAi/HNX9BjebWvVgd7B2OpDWAq4QFLrdSlBqT8d+V1IuJeztcjKhe5lHxHDiE6/5ajmBs4/c0EmKN7bXC+fF7xbVLa+aiKQCW7rzldXx0aqP/6/+VYAXrre55nIWzuArciLT43G1DzDRTyWz+KtNm9CYd07bn1QA9a3bvQxpuM3KSo2fyfBQTcxapBNDoMnM4gKUNd3rTdDmC0j2bHN9Ikyef9ohWzgIkmLleh8Ey1TpGbWS3Y2B3AD2bmqxWgzUBUMkenmp1GglHtc448BuusPPAcibIntZMQqmaHoJ1zeNJQKGNUKCJFjbe/aeHBm/jJ7izPfR8W27D+NMhdvFOZjprmh1AVa97yQ5Zqbh1zH/gsL0XCEuNOobVaVjAsOBhXMiFnl4U4sjknE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>");

                _BackgroundWorker = new BackgroundWorker();
                _BackgroundWorker.WorkerReportsProgress = true;
                _BackgroundWorker.ProgressChanged      += _BackgroundWorker_ProgressChanged;
                _BackgroundWorkerAutoResetEvent         = new AutoResetEvent(false);
                _BackgroundWorker.DoWork += delegate(object sender, DoWorkEventArgs e)
                {
                    _BackgroundWorkerAutoResetEvent.WaitOne();
                };
                _BackgroundWorker.RunWorkerAsync();

                string debugFileName = host.CommandLineArgs["KPRPCDebug"];
                if (debugFileName != null)
                {
                    try
                    {
                        logger = new StreamWriter(debugFileName);
                        ((StreamWriter)logger).AutoFlush = true;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("KeePassRPC debug logger failed to initialise. No logging will be performed until KeePass is restarted with a valid debug log file location. Reason: " + ex.ToString());
                    }
                }
                if (logger != null)
                {
                    logger.WriteLine("Logger initialised.");
                }

                TLDRulesCache.Init(host.CustomConfig.GetString(
                                       "KeePassRPC.publicSuffixDomainCache.path",
                                       GetLocalConfigLocation() + "publicSuffixDomainCache.txt"));

                // The Kee client manager holds objects relating to the web socket connections managed by the Fleck2 library
                CreateClientManagers();

                if (logger != null)
                {
                    logger.WriteLine("Client managers started.");
                }
                //TODO2: set up language services

                _RPCService = new KeePassRPCService(host,
                                                    getStandardIconsBase64(host.MainWindow.ClientIcons), this);
                if (logger != null)
                {
                    logger.WriteLine("RPC service started.");
                }
                int portNew = FindKeePassRPCPort(host);

                try
                {
                    WebSocketServerConfig config = new WebSocketServerConfig();
                    config.WebSocketPort      = portNew;
                    config.BindOnlyToLoopback = host.CustomConfig.GetBool("KeePassRPC.webSocket.bindOnlyToLoopback", true);
                    config.PermittedOrigins   = DeterminePermittedOrigins();
                    _RPCServer = new KeePassRPCServer(RPCService, this, config);
                }
                catch (System.Net.Sockets.SocketException ex)
                {
                    if (ex.SocketErrorCode == System.Net.Sockets.SocketError.AddressAlreadyInUse)
                    {
                        MessageBox.Show(@"KeePassRPC is already listening for connections. To allow KeePassRPC clients (e.g. Kee in your web browser) to connect to this instance of KeePass, please close all other running instances of KeePass and restart this KeePass. If you want multiple instances of KeePass to be running at the same time, you'll need to configure some of them to connect using a different communication port.

See https://forum.kee.pm/t/connection-security-levels/1075

KeePassRPC requires this port to be available: " + portNew + ". Technical detail: " + ex.ToString());
                        if (logger != null)
                        {
                            logger.WriteLine("Socket (port) already in use. KeePassRPC requires this port to be available: " + portNew + ". Technical detail: " + ex.ToString());
                        }
                    }
                    else
                    {
                        MessageBox.Show(@"KeePassRPC could not start listening for connections. To allow KeePassRPC clients (e.g. Kee in your web browser) to connect to this instance of KeePass, please fix the problem indicated in the technical detail below and restart KeePass.

KeePassRPC requires this port to be available: " + portNew + ". Technical detail: " + ex.ToString());
                        if (logger != null)
                        {
                            logger.WriteLine("Socket error. KeePassRPC requires this port to be available: " + portNew + ". Maybe check that you have no firewall or other third party security software interfering with your system. Technical detail: " + ex.ToString());
                        }
                    }
                    if (logger != null)
                    {
                        logger.WriteLine("KPRPC startup failed: " + ex.ToString());
                    }
                    _BackgroundWorkerAutoResetEvent.Set(); // terminate _BackgroundWorker
                    return(false);
                }
                if (logger != null)
                {
                    logger.WriteLine("RPC server started.");
                }

                // register to recieve events that we need to deal with

                _host.MainWindow.FileOpened  += OnKPDBOpen;
                _host.MainWindow.FileClosed  += OnKPDBClose;
                _host.MainWindow.FileCreated += OnKPDBCreated;
                _host.MainWindow.FileSaving  += OnKPDBSaving;
                _host.MainWindow.FileSaved   += OnKPDBSaved;

                _host.MainWindow.DocumentManager.ActiveDocumentSelected += OnKPDBSelected;

                // Get a reference to the 'Tools' menu item container
                ToolStripItemCollection tsMenu = _host.MainWindow.ToolsMenu.DropDownItems;

                // Add menu item for options
                _keePassRPCOptions        = new DPIScaledToolStripMenuItem("KeePassRPC (Kee) Options...");
                _keePassRPCOptions.Click += OnToolsOptions;
                tsMenu.Add(_keePassRPCOptions);

                // Add a seperator and menu item to the group context menu
                ContextMenuStrip gcm = host.MainWindow.GroupContextMenu;
                _tsSeparator1 = new ToolStripSeparator();
                gcm.Items.Add(_tsSeparator1);
                _keeRootMenu        = new DPIScaledToolStripMenuItem("Set as Kee home group");
                _keeRootMenu.Click += OnMenuSetRootGroup;
                gcm.Items.Add(_keeRootMenu);

                // not acting on upgrade info just yet but we need to track it for future proofing
                bool upgrading = refreshVersionInfo(host);

                // for debug only:
                //WelcomeForm wf = new WelcomeForm();
                //DialogResult dr = wf.ShowDialog();
                //if (dr == DialogResult.Yes)
                //    CreateNewDatabase();

                GwmWindowAddedHandler            = new EventHandler <GwmWindowEventArgs>(GlobalWindowManager_WindowAdded);
                GlobalWindowManager.WindowAdded += GwmWindowAddedHandler;
            }
            catch (Exception ex)
            {
                if (logger != null)
                {
                    logger.WriteLine("KPRPC startup failed: " + ex.ToString());
                }
                _BackgroundWorkerAutoResetEvent.Set(); // terminate _BackgroundWorker
                return(false);
            }
            if (logger != null)
            {
                logger.WriteLine("KPRPC startup succeeded.");
            }
            return(true); // Initialization successful
        }
Пример #8
0
        internal void MessageRPCClientConnection(IWebSocketConnection webSocket, string message, KeePassRPCService service)
        {
            KeePassRPCClientConnection connection = null;

            lock (_lockRPCClientManagers)
            {
                _lockRPCClientManagers.HeldBy = Thread.CurrentThread.ManagedThreadId;
                foreach (KeePassRPCClientManager manager in _RPCClientManagers.Values)
                {
                    foreach (KeePassRPCClientConnection conn in manager.CurrentRPCClientConnections)
                    {
                        if (conn.WebSocketConnection == webSocket)
                        {
                            connection = conn;
                            break;
                        }
                    }
                    if (connection != null)
                    {
                        break;
                    }
                }
            }

            if (connection != null)
            {
                connection.ReceiveMessage(message, service);
            }
            else
            {
                webSocket.Close();
            }
        }
Пример #9
0
        /// <summary>
        /// Establishes the SSL certificate we will use for communication with
        /// RPC clients and starts a seperate thread to listen for connections
        /// </summary>
        /// <param name="port">port to listen on</param>
        /// <param name="service">The KeePassRPCService the server should interact with.</param>
        public KeePassRPCServer(int port, KeePassRPCService service, KeePassRPCExt keePassRPCPlugin, bool useSSL)
        {
            _useSSL = useSSL;
            if (keePassRPCPlugin.logger != null)
            {
                keePassRPCPlugin.logger.WriteLine("Starting KPRPCServer");
            }
            Service          = service;
            KeePassRPCPlugin = keePassRPCPlugin;

            if (_useSSL)
            {
//                if (true)
                if (Type.GetType("Mono.Runtime") == null)
                {
                    _store = new System.Security.Cryptography.X509Certificates.X509Store();
                    _store.Open(OpenFlags.ReadWrite);

                    // Find any certificates in this user's certificate store and re-use
                    // them rather than suffer the overhead of creating an entirly new
                    // certificate. Our certificates are considered "invalid" by the
                    // store (probably becuase they are self-signed)
                    X509Certificate2Collection matchingCertificates = _store.Certificates
                                                                      .Find(X509FindType.FindBySubjectDistinguishedName,
                                                                            "CN=KeePassRPC certificate for " + Environment.MachineName, false);

                    //foreach (X509Certificate2 temp in matchingCertificates)
                    //    _store.Remove(temp);

                    //matchingCertificates = _store.Certificates
                    //    .Find(X509FindType.FindBySubjectDistinguishedName,
                    //        "CN=KeePassRPC TLS aaa for " + Environment.MachineName, false);

                    if (keePassRPCPlugin.logger != null)
                    {
                        keePassRPCPlugin.logger.WriteLine("Matching certificates from store: " + matchingCertificates.Count);
                    }
                    if (matchingCertificates.Count > 0)
                    {
                        _serverCertificate = matchingCertificates[0];
                    }
                    else
                    {
                        //_serverCertificate = (X509Certificate2)X509Certificate2.CreateFromCertFile(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "KeePassRPC"), "cert.p12"));

                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Generating new certificate (MS).");
                        }
                        // We can use the MakeCert feature from Mono to generate a new
                        // certificate for use by this user on this machine. This means
                        // that every KeePassRPC user will establish TLS connections
                        // that are protected by a private key held on their own
                        // system, rather than a key that is disclosed in this open
                        // source code. NB: The local server is assumed to be secure!
                        PKCS12 p12  = MakeCertKPRPC.Generate("KeePassRPC certificate for " + Environment.MachineName, "KeePassRPC Automated Self-Signed Key Generator", keePassRPCPlugin);
                        byte[] cert = p12.GetBytes();
                        _serverCertificate = new X509Certificate2(cert, (string)null, X509KeyStorageFlags.PersistKeySet);
                        _store.Add(_serverCertificate);
                    }
                }
                else
                {
                    /*
                     * Problem 1:
                     *   For Linux/Mono, we cannot use the X509Store. It appears that only a .cer file is saved. That certificate does not include
                     *   the private key that we need for SSL. So we will need to save the key ourselves.
                     *
                     * Problem 2:
                     *   When using PKCS12 SaveToFile to save the key ourselves, it appears that it is not possible to save a private key that is not
                     *   password protected.
                     *
                     */
                    string certdir  = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "KeePassRPC");
                    string certfile = Path.Combine(certdir, "cert.p12");
                    _serverCertificate = null;

                    // Check if cert directory exists, if not, we need to create it
                    if (!System.IO.Directory.Exists(certdir))
                    {
                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Cert directory does not exist, creating " + certdir);
                        }

                        System.IO.Directory.CreateDirectory(certdir);

                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Cert directory created");
                        }
                    }
                    else
                    {
                        // Attempt to load cert
                        try {
                            if (keePassRPCPlugin.logger != null)
                            {
                                keePassRPCPlugin.logger.WriteLine("Looking for existing certificate (Mono)");
                            }
                            _serverCertificate = new X509Certificate2();
                            _serverCertificate.Import(certfile, pkcs12_password, X509KeyStorageFlags.PersistKeySet);
                            if (keePassRPCPlugin.logger != null)
                            {
                                keePassRPCPlugin.logger.WriteLine("Existing certificate loaded(Mono) : " + certfile);
                            }
                        }
                        catch (Exception ex) {
                            _serverCertificate = null;
                        }
                    }
                    // If we didn't load a cert, create one and save it
                    if (_serverCertificate == null)
                    {
                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Generating new certificate (Mono).");
                        }

                        PKCS12 p12 = MakeCertKPRPC.Generate("KeePassRPC certificate for " + Environment.MachineName, "KeePassRPC Automated Self-Signed Key Generator", pkcs12_password, keePassRPCPlugin);
                        p12.SaveToFile(certfile);
                        byte[] cert = p12.GetBytes();
                        _serverCertificate = new X509Certificate2(cert, pkcs12_password, X509KeyStorageFlags.PersistKeySet);
                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Generated new certificate (Mono) : " + certfile);
                        }
                    }
                }
            }

            if (keePassRPCPlugin.logger != null)
            {
                keePassRPCPlugin.logger.WriteLine("Server certificate has private key? " + _serverCertificate.HasPrivateKey);
            }

            try
            {
                this._tcpListener  = new TcpListener(IPAddress.Loopback, port);
                this._listenThread = new Thread(new ThreadStart(ListenForClients));
                this._listenThread.Start();
                this._isListening = true; // just in case the main thread checks
                // for successful startup before the thread has got going.
            }
            catch (Exception e)
            {
                if (keePassRPCPlugin.logger != null)
                {
                    keePassRPCPlugin.logger.WriteLine("Failed to start TCP listener: " + e.ToString());
                }
            }
            if (keePassRPCPlugin.logger != null)
            {
                keePassRPCPlugin.logger.WriteLine("Started KPRPCServer");
            }
        }
Пример #10
0
        /// <summary>
        /// The <c>Initialize</c> function is called by KeePass when
        /// you should initialize your plugin (create menu items, etc.).
        /// </summary>
        /// <param name="host">Plugin host interface. By using this
        /// interface, you can access the KeePass main window and the
        /// currently opened database.</param>
        /// <returns>true if channel registered correctly, otherwise false</returns>
        public override bool Initialize(IPluginHost host)
        {
            try
            {
                Debug.Assert(host != null);
                if (host == null)
                {
                    return(false);
                }
                _host = host;

                string debugFileName = host.CommandLineArgs["KPRPCDebug"];
                if (debugFileName != null)
                {
                    try
                    {
                        logger = new StreamWriter(debugFileName);
                        ((StreamWriter)logger).AutoFlush = true;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("KeePassRPC debug logger failed to initialise. No logging will be performed until KeePass is restarted with a valid debug log file location. Reason: " + ex.ToString());
                    }
                }
                if (logger != null)
                {
                    logger.WriteLine("Logger initialised.");
                }

                //AppDomain.CurrentDomain.AssemblyResolve +=
                //new ResolveEventHandler(CurrentDomain_AssemblyResolve);



                CreateClientManagers();

                if (logger != null)
                {
                    logger.WriteLine("Client managers started.");
                }
                //TODO2: set up language services

                _RPCService = new KeePassRPCService(host,
                                                    getStandardIconsBase64(host.MainWindow.ClientIcons), this);
                if (logger != null)
                {
                    logger.WriteLine("RPC service started.");
                }
                _RPCServer = new KeePassRPCServer(FindKeePassRPCPort(host), RPCService, this, FindKeePassRPCSSLEnabled(host));
                if (logger != null)
                {
                    logger.WriteLine("RPC server started.");
                }

                // register to recieve events that we need to deal with

                _host.MainWindow.FileOpened  += OnKPDBOpen;
                _host.MainWindow.FileClosed  += OnKPDBClose;
                _host.MainWindow.FileCreated += OnKPDBOpen; // or need a specific handler here?

                //be nice to pick up when entries are edited and update the firefox URL cache imemdiately
                //for the time being we'll have to hook onto the Save function
                //ServerData.m_host.Database.RootGroup...
                _host.MainWindow.FileSaving += OnKPDBSaving;
                _host.MainWindow.FileSaved  += OnKPDBSaved;

                _host.MainWindow.DocumentManager.ActiveDocumentSelected += OnKPDBSelected;

                // Get a reference to the 'Tools' menu item container
                ToolStripItemCollection tsMenu = _host.MainWindow.ToolsMenu.DropDownItems;

                // Add menu item for options
                _keePassRPCOptions         = new ToolStripMenuItem();
                _keePassRPCOptions.Text    = "KeePassRPC (KeeFox) Options...";
                _keePassRPCOptions.Click  += OnToolsOptions;
                _keePassRPCOptions.Enabled = true;
                tsMenu.Add(_keePassRPCOptions);

                // Add menu item for KeeFox samples
                _keeFoxSampleEntries         = new ToolStripMenuItem();
                _keeFoxSampleEntries.Text    = "Insert KeeFox tutorial samples";
                _keeFoxSampleEntries.Click  += OnToolsInstallKeeFoxSampleEntries;
                _keeFoxSampleEntries.Enabled = true;
                tsMenu.Add(_keeFoxSampleEntries);

                // Add a seperator and menu item to the group context menu
                ContextMenuStrip gcm = host.MainWindow.GroupContextMenu;
                _tsSeparator1 = new ToolStripSeparator();
                gcm.Items.Add(_tsSeparator1);
                _keeFoxRootMenu        = new ToolStripMenuItem();
                _keeFoxRootMenu.Text   = "Set as KeeFox start group";
                _keeFoxRootMenu.Click += OnMenuSetRootGroup;
                gcm.Items.Add(_keeFoxRootMenu);

                // not acting on upgrade info just yet but we need to track it for future proofing
                bool upgrading = refreshVersionInfo(host);

                if (!_RPCServer.IsListening)
                {
                    MessageBox.Show("Could not start listening for RPC connections. KeePassRPC will not function and any services that rely on it will fail to connect to KeePass.");
                }

                // for debug only:
                //WelcomeForm wf = new WelcomeForm();
                //DialogResult dr = wf.ShowDialog();
                //if (dr == DialogResult.Yes)
                //    CreateNewDatabase();

                GwmWindowAddedHandler            = new EventHandler <GwmWindowEventArgs>(GlobalWindowManager_WindowAdded);
                GlobalWindowManager.WindowAdded += GwmWindowAddedHandler;
            }
            catch (Exception ex)
            {
                if (logger != null)
                {
                    logger.WriteLine("KPRPC startup failed: " + ex.ToString());
                }
                return(false);
            }
            if (logger != null)
            {
                logger.WriteLine("KPRPC startup succeeded.");
            }
            return(true);            // Initialization successful
        }
Пример #11
0
        /// <summary>
        /// Establishes the SSL certificate we will use for communication with
        /// RPC clients and starts a seperate thread to listen for connections
        /// </summary>
        /// <param name="port">port to listen on</param>
        /// <param name="service">The KeePassRPCService the server should interact with.</param>
        public KeePassRPCServer(int port, KeePassRPCService service, KeePassRPCExt keePassRPCPlugin, bool useSSL)
        {
            _useSSL = useSSL;
            if (keePassRPCPlugin.logger != null)
            {
                keePassRPCPlugin.logger.WriteLine("Starting KPRPCServer");
            }
            Service          = service;
            KeePassRPCPlugin = keePassRPCPlugin;

            if (_useSSL)
            {
                if (Type.GetType("Mono.Runtime") == null)
                {
                    _store = new X509Store();
                    _store.Open(OpenFlags.ReadWrite);

                    // Find any certificates in this user's certificate store and re-use
                    // them rather than suffer the overhead of creating an entirly new
                    // certificate. Our certificates are considered "invalid" by the
                    // store (probably becuase they are self-signed)
                    X509Certificate2Collection matchingCertificates = _store.Certificates
                                                                      .Find(X509FindType.FindBySubjectDistinguishedName,
                                                                            "CN=KeePassRPC certificate for " + Environment.MachineName, false);

                    //foreach (X509Certificate2 temp in matchingCertificates)
                    //    _store.Remove(temp);

                    //matchingCertificates = _store.Certificates
                    //    .Find(X509FindType.FindBySubjectDistinguishedName,
                    //        "CN=KeePassRPC TLS aaa for " + Environment.MachineName, false);

                    if (keePassRPCPlugin.logger != null)
                    {
                        keePassRPCPlugin.logger.WriteLine("Matching certificates from store: " + matchingCertificates.Count);
                    }
                    if (matchingCertificates.Count > 0)
                    {
                        _serverCertificate = matchingCertificates[0];
                    }
                    else
                    {
                        //_serverCertificate = (X509Certificate2)X509Certificate2.CreateFromCertFile(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "KeePassRPC"), "cert.p12"));

                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Generating new certificate (MS).");
                        }
                        // We can use the MakeCert feature from Mono to generate a new
                        // certificate for use by this user on this machine. This means
                        // that every KeePassRPC user will establish TLS connections
                        // that are protected by a private key held on their own
                        // system, rather than a key that is disclosed in this open
                        // source code. NB: The local server is assumed to be secure!
                        byte[] cert = MakeCertKPRPC.Generate("KeePassRPC certificate for " + Environment.MachineName, "KeePassRPC Automated Self-Signed Key Generator", keePassRPCPlugin);
                        _serverCertificate = new X509Certificate2(cert, (string)null, X509KeyStorageFlags.PersistKeySet);
                        _store.Add(_serverCertificate);
                    }
                }
                else
                {
                    if (keePassRPCPlugin.logger != null)
                    {
                        keePassRPCPlugin.logger.WriteLine("Looking for existing certificate (Mono)");
                    }

                    _serverCertificate = (X509Certificate2)X509Certificate2.CreateFromCertFile(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "KeePassRPC"), "cert.p12"));

                    if (_serverCertificate == null)
                    {
                        if (keePassRPCPlugin.logger != null)
                        {
                            keePassRPCPlugin.logger.WriteLine("Generating new certificate (Mono).");
                        }

                        MakeCertKPRPC.Generate("KeePassRPC certificate for " + Environment.MachineName, "KeePassRPC Automated Self-Signed Key Generator", keePassRPCPlugin);
                        _serverCertificate = (X509Certificate2)X509Certificate2.CreateFromCertFile(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "KeePassRPC"), "cert.p12"));
                    }
                }
            }
            if (keePassRPCPlugin.logger != null)
            {
                keePassRPCPlugin.logger.WriteLine("Server certificate has private key? " + _serverCertificate.HasPrivateKey);
            }

            try
            {
                this._tcpListener  = new TcpListener(IPAddress.Loopback, port);
                this._listenThread = new Thread(new ThreadStart(ListenForClients));
                this._listenThread.Start();
                this._isListening = true; // just in case the main thread checks
                // for successful startup before the thread has got going.
            }
            catch (Exception e)
            {
                if (keePassRPCPlugin.logger != null)
                {
                    keePassRPCPlugin.logger.WriteLine("Failed to start TCP listener: " + e.ToString());
                }
            }
            if (keePassRPCPlugin.logger != null)
            {
                keePassRPCPlugin.logger.WriteLine("Started KPRPCServer");
            }
        }