コード例 #1
0
        public virtual void UploadNotes(IList <Note> notes)
        {
            if (Directory.Exists(newRevisionPath) == false)
            {
                DirectoryInfo info = Directory.CreateDirectory(newRevisionPath);
                AdjustPermissions(info.Parent.FullName);
                AdjustPermissions(newRevisionPath);
            }
            Logger.Debug("UploadNotes: notes.Count = {0}", notes.Count);
            foreach (Note note in notes)
            {
                try
                {
                    string serverNotePath = Path.Combine(newRevisionPath, Path.GetFileName(note.FilePath));
                    SecurityWrapper.CopyAndEncrypt(note.FilePath, serverNotePath, myKey);
                    //File.Copy(note.FilePath, serverNotePath, true);

                    // upload to webdav takes place in commit-function
                    AdjustPermissions(serverNotePath);
                    updatedNotes.Add(Path.GetFileNameWithoutExtension(note.FilePath));
                }
                catch (Exception e)
                {
                    Logger.Error("Sync: Error uploading note \"{0}\": {1}", note.Title, e.Message);
                }
            }
        }
コード例 #2
0
        public IList <string> GetAllNoteUUIDs()
        {
            List <string> noteUUIDs = new List <string>();

            if (IsValidXmlFile(manifestPath))
            {
                // TODO: Permission errors
                using (FileStream fs = new FileStream(manifestPath, FileMode.Open))
                {
                    bool   ok;
                    Stream plainStream = SecurityWrapper.DecryptFromStream(manifestPath, fs, myKey, out ok);
                    if (!ok)
                    {
                        throw new EncryptionException("ENCRYPTION ERROR");
                    }

                    XmlDocument doc = new XmlDocument();
                    doc.Load(plainStream);

                    XmlNodeList noteIds = doc.SelectNodes("//note/@id");
                    Logger.Debug("GetAllNoteUUIDs has {0} notes", noteIds.Count);
                    foreach (XmlNode idNode in noteIds)
                    {
                        noteUUIDs.Add(idNode.InnerText);
                    }
                }
            }

            return(noteUUIDs);
        }
コード例 #3
0
        /// <summary>
        /// Check that xmlFilePath points to an existing valid XML file.
        /// This is done by ensuring that an XmlDocument can be created from
        /// its contents.
        ///</summary>
        private bool IsValidXmlFile(string xmlFilePath)
        {
            // Check that file exists
            if (!File.Exists(xmlFilePath))
            {
                return(false);
            }

            // TODO: Permissions errors
            // Attempt to load the file and parse it as XML
            try
            {
                using (FileStream fs = new FileStream(xmlFilePath, FileMode.Open))
                {
                    bool   ok;
                    Stream plainStream = SecurityWrapper.DecryptFromStream(xmlFilePath, fs, myKey, out ok);
                    if (!ok)
                    {
                        throw new EncryptionException("ENCRYPTION ERROR!");
                    }

                    XmlDocument doc = new XmlDocument();
                    // TODO: Make this be a validating XML reader.	Not sure if it's validating yet.
                    doc.Load(plainStream);
                }
            }
            catch (PasswordException)
            {
                throw;
            }
            catch (EncryptionException ee)
            {
                throw new Exception("there was a problem with the file encryption, can't sync!", ee);
            }
            catch (Exception e)
            {
                Logger.Debug("Exception while validating lock file: " + e.ToString());
                return(false);
            }

            return(true);
        }
コード例 #4
0
        public virtual bool CommitSyncTransaction()
        {
            bool commitSucceeded = false;

            if (updatedNotes.Count > 0 || deletedNotes.Count > 0)
            {
                // TODO: error-checking, etc
                string manifestFilePath = Path.Combine(newRevisionPath,
                                                       "manifest.xml");
                if (!Directory.Exists(newRevisionPath))
                {
                    DirectoryInfo info = Directory.CreateDirectory(newRevisionPath);
                    AdjustPermissions(info.Parent.FullName);
                    AdjustPermissions(newRevisionPath);
                }

                XmlNodeList noteNodes = null;
                if (IsValidXmlFile(manifestPath) == true)
                {
                    using (FileStream fs = new FileStream(manifestPath, FileMode.Open))
                    {
                        bool   ok;
                        Stream plainStream = SecurityWrapper.DecryptFromStream(manifestPath, fs, myKey, out ok);
                        if (!ok)
                        {
                            throw new Exception("ENCRYPTION ERROR!");
                        }

                        XmlDocument doc = new XmlDocument();
                        doc.Load(plainStream);
                        noteNodes = doc.SelectNodes("//note");
                    }
                }
                else
                {
                    using (StringReader sr = new StringReader("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<sync>\n</sync>"))
                    {
                        XmlDocument doc = new XmlDocument();
                        doc.Load(sr);
                        noteNodes = doc.SelectNodes("//note");
                    }
                }

                #region createManifestFile
                // Write out the new manifest file
                MemoryStream plainBuf = new MemoryStream();
                XmlWriter    xml      = XmlWriter.Create(plainBuf, XmlEncoder.DocumentSettings);
                try
                {
                    xml.WriteStartDocument();
                    xml.WriteStartElement(null, "sync", null);
                    xml.WriteAttributeString("revision", newRevision.ToString());
                    xml.WriteAttributeString("server-id", serverId);

                    foreach (XmlNode node in noteNodes)
                    {
                        string id  = node.SelectSingleNode("@id").InnerText;
                        string rev = node.SelectSingleNode("@rev").InnerText;

                        // Don't write out deleted notes
                        if (deletedNotes.Contains(id))
                        {
                            continue;
                        }

                        // Skip updated notes, we'll update them in a sec
                        if (updatedNotes.Contains(id))
                        {
                            continue;
                        }

                        xml.WriteStartElement(null, "note", null);
                        xml.WriteAttributeString("id", id);
                        xml.WriteAttributeString("rev", rev);
                        xml.WriteEndElement();
                    }

                    // Write out all the updated notes
                    foreach (string uuid in updatedNotes)
                    {
                        xml.WriteStartElement(null, "note", null);
                        xml.WriteAttributeString("id", uuid);
                        xml.WriteAttributeString("rev", newRevision.ToString());
                        xml.WriteEndElement();
                    }

                    xml.WriteEndElement();
                    xml.WriteEndDocument();
                }
                finally
                {
                    xml.Close();
                    // now store in encrypted version:
                    SecurityWrapper.SaveAsEncryptedFile(manifestFilePath, plainBuf.ToArray(), myKey);
                    // dispose of plain data
                    plainBuf.Dispose();
                }

                AdjustPermissions(manifestFilePath);
                #endregion

                // only use this if we use the revision-folder-mode
                if (!manifestFilePath.Equals(manifestPath))
                {
                    #region DIR_VERSION
                    // Rename original /manifest.xml to /manifest.xml.old
                    string oldManifestPath = manifestPath + ".old";
                    if (File.Exists(manifestPath) == true)
                    {
                        if (File.Exists(oldManifestPath))
                        {
                            File.Delete(oldManifestPath);
                        }
                        File.Move(manifestPath, oldManifestPath);
                    }


                    // * * * Begin Cleanup Code * * *
                    // TODO: Consider completely discarding cleanup code, in favor
                    //			 of periodic thorough server consistency checks (say every 30 revs).
                    //			 Even if we do continue providing some cleanup, consistency
                    //			 checks should be implemented.

                    // Copy the /${parent}/${rev}/manifest.xml -> /manifest.xml
                    // don't encrypt here because file is already encrypted!
                    //SecurityWrapper.CopyAndEncrypt(manifestFilePath, manifestPath, myKey);
                    File.Copy(manifestFilePath, manifestPath, true);
                    AdjustPermissions(manifestPath);

                    try
                    {
                        // Delete /manifest.xml.old
                        if (File.Exists(oldManifestPath))
                        {
                            File.Delete(oldManifestPath);
                        }

                        string oldManifestFilePath = Path.Combine(GetRevisionDirPath(newRevision - 1),
                                                                  "manifest.xml");

                        if (File.Exists(oldManifestFilePath))
                        {
                            // TODO: Do step #8 as described in http://bugzilla.gnome.org/show_bug.cgi?id=321037#c17
                            // Like this?
                            FileInfo oldManifestFilePathInfo = new FileInfo(oldManifestFilePath);
                            foreach (FileInfo file in oldManifestFilePathInfo.Directory.GetFiles())
                            {
                                string fileGuid = Path.GetFileNameWithoutExtension(file.Name);
                                if (deletedNotes.Contains(fileGuid) ||
                                    updatedNotes.Contains(fileGuid))
                                {
                                    File.Delete(file.FullName);
                                }
                                // TODO: Need to check *all* revision dirs, not just previous (duh)
                                //			 Should be a way to cache this from checking earlier.
                            }

                            // TODO: Leaving old empty dir for now.	Some stuff is probably easier
                            //			 when you can guarantee the existence of each intermediate directory?
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Exception during server cleanup while committing. " +
                                     "Server integrity is OK, but there may be some excess " +
                                     "files floating around.	Here's the error:\n"+
                                     e.Message);
                    }
                    #endregion
                }
                else
                {
                    Logger.Info("probably doing sync without revision-hierarchy");

                    OnManifestFileCreated(manifestFilePath);

                    // this is just a simple cleanup because we only use one directory
                    // delete the notes that were deleted in this one directory:
                    try
                    {
                        FileInfo manifestFilePathInfo = new FileInfo(manifestFilePath);
                        foreach (FileInfo file in manifestFilePathInfo.Directory.GetFiles())
                        {
                            string fileGuid = Path.GetFileNameWithoutExtension(file.Name);
                            if (deletedNotes.Contains(fileGuid))
                            {
                                File.Delete(file.FullName);
                                OnDeleteFile(file.FullName);
                            }

                            if (updatedNotes.Contains(fileGuid))
                            {
                                OnUploadFile(file.FullName);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Exception during server cleanup while committing. " +
                                     "Server integrity is OK, but there may be some excess " +
                                     "files floating around.	Here's the error:\n"+
                                     e.Message);
                    }
                }
            }
            else
            {
                // no changes (no updates/deletes)
            }

            lockTimeout.Cancel();
            RemoveLockFile(lockPath);
            commitSucceeded = true;                    // TODO: When return false?
            return(commitSucceeded);
        }
コード例 #5
0
        public virtual IDictionary <string, NoteUpdate> GetNoteUpdatesSince(int revision)
        {
            Dictionary <string, NoteUpdate> noteUpdates = new Dictionary <string, NoteUpdate>();

            if (IsValidXmlFile(manifestPath))
            {
                // TODO: Permissions errors
                using (FileStream fs = new FileStream(manifestPath, FileMode.Open))
                {
                    Stream plainStream;
                    {
                        bool ok;
                        plainStream = SecurityWrapper.DecryptFromStream(manifestPath, fs, myKey, out ok);
                        if (!ok)
                        {
                            throw new Exception("ENCRYPTION ERROR!");
                        }
                    }

                    XmlDocument doc = new XmlDocument();
                    doc.Load(plainStream);

                    string xpath =
                        string.Format("//note[@rev > {0}]", revision.ToString());
                    XmlNodeList noteNodes = doc.SelectNodes(xpath);
                    Logger.Debug("GetNoteUpdatesSince xpath returned {0} nodes", noteNodes.Count);
                    foreach (XmlNode node in noteNodes)
                    {
                        string id  = node.SelectSingleNode("@id").InnerText;
                        int    rev = Int32.Parse(node.SelectSingleNode("@rev").InnerText);
                        if (noteUpdates.ContainsKey(id) == false)
                        {
                            // Copy the file from the server to the temp directory
                            string revDir         = GetRevisionDirPath(rev);
                            string serverNotePath = Path.Combine(revDir, id + ".note");
                            //string noteTempPath = Path.Combine(tempPath, id + ".note");
                            // DON'T ENCRYPT HERE because we are getting the already encrypted file from the server
                            //SecurityWrapper.CopyAndEncrypt(serverNotePath, noteTempPath, myKey);
                            //File.Copy(serverNotePath, noteTempPath, true);

                            // Get the title, contents, etc.
                            string noteTitle = string.Empty;
                            string noteXml   = null;

                            {
                                // decrypt the note:
                                bool         ok;
                                CryptoFormat ccf      = CryptoFormatProviderFactory.INSTANCE.GetCryptoFormat();
                                byte[]       contents = ccf.DecryptFile(serverNotePath, myKey, out ok);
                                noteXml = Util.FromBytes(contents);

                                // solve nasty BOM problem -__-
                                int index = noteXml.IndexOf('<');
                                if (index > 0)
                                {
                                    noteXml = noteXml.Substring(index, noteXml.Length - index);
                                }
                            }
                            NoteUpdate update = new NoteUpdate(noteXml, noteTitle, id, rev);
                            noteUpdates[id] = update;
                        }
                    }
                }
            }

            Logger.Debug("GetNoteUpdatesSince ({0}) returning: {1}", revision, noteUpdates.Count);
            return(noteUpdates);
        }