public void AddOrUpdate(string service, string account, string secret)
        {
            // Ensure the store root exists and permissions are set
            EnsureStoreRoot();

            string serviceSlug = CreateServiceSlug(service);
            string servicePath = Path.Combine(StoreRoot, serviceSlug);

            if (!FileSystem.DirectoryExists(servicePath))
            {
                FileSystem.CreateDirectory(servicePath);
            }

            string fullPath   = Path.Combine(servicePath, $"{account}{CredentialFileExtension}");
            var    credential = new FileCredential(fullPath, service, account, secret);

            SerializeCredential(credential);
        }
        protected virtual void SerializeCredential(FileCredential credential)
        {
            // Ensure the parent directory exists
            string parentDir = Path.GetDirectoryName(credential.FullPath);

            if (!FileSystem.DirectoryExists(parentDir))
            {
                FileSystem.CreateDirectory(parentDir);
            }

            using (var stream = FileSystem.OpenFileStream(credential.FullPath, FileMode.Create, FileAccess.Write, FileShare.None))
                using (var writer = new StreamWriter(stream))
                {
                    writer.WriteLine(credential.Password);
                    writer.WriteLine("service={0}", credential.Service);
                    writer.WriteLine("account={0}", credential.Account);
                    writer.Flush();
                }
        }
        protected virtual bool TryDeserializeCredential(string path, out FileCredential credential)
        {
            string text;

            using (var stream = FileSystem.OpenFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (var reader = new StreamReader(stream))
                {
                    text = reader.ReadToEnd();
                }

            int line1Idx = text.IndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase);

            if (line1Idx > 0)
            {
                // Password is the first line
                string password = text.Substring(0, line1Idx);

                // All subsequent lines are metadata/attributes
                string attrText = text.Substring(line1Idx + Environment.NewLine.Length);
                using var attrReader = new StringReader(attrText);
                IDictionary <string, string> attrs = attrReader.ReadDictionary(StringComparer.OrdinalIgnoreCase);

                // Account is optional
                attrs.TryGetValue("account", out string account);

                // Service is required
                if (attrs.TryGetValue("service", out string service))
                {
                    credential = new FileCredential(path, service, account, password);
                    return(true);
                }
            }

            credential = null;
            return(false);
        }