Beispiel #1
0
        private async Task RoundTrip()
        {
            ReaderResult initialHeaderResult = await this.reader.ReadHeaderAsync(await this.thisTestInfo.Database.AsIStorageFile.OpenReadAsync(), CancellationToken.None);

            Assert.AreEqual(ReaderResult.Success, initialHeaderResult, "Initial header read should be successful");

            KdbxDecryptionResult result = await this.reader.DecryptFileAsync(await this.thisTestInfo.Database.AsIStorageFile.OpenReadAsync(), this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None);

            Assert.AreEqual(ReaderResult.Success, result.Result, "File should have initially decrypted properly");
            KdbxDocument kdbxDoc = result.GetDocument();
            IKdbxWriter  writer  = this.reader.GetWriter();

            using (var stream = new InMemoryRandomAccessStream())
            {
                bool writeResult = await writer.WriteAsync(stream, kdbxDoc, CancellationToken.None);

                Assert.IsTrue(writeResult, "File should have written successfully");

                stream.Seek(0);
                KdbxReader   newReader = new KdbxReader();
                ReaderResult result2   = await newReader.ReadHeaderAsync(stream, CancellationToken.None);

                Assert.AreEqual(ReaderResult.Success, result2, "Header should been read back successfully after write");

                KdbxDecryptionResult result3 = await newReader.DecryptFileAsync(stream, this.thisTestInfo.Password, this.thisTestInfo.Keyfile, CancellationToken.None);

                Assert.AreEqual(ReaderResult.Success, result3.Result, "File should have decrypted successfully after write");

                KdbxDocument roundTrippedDocument = result3.GetDocument();
                Assert.AreEqual(kdbxDoc, roundTrippedDocument, "Round-tripped document should be equal to original document");
            }
        }
Beispiel #2
0
        /// <summary>
        /// Parses the header of the CandidateFile and handles updating status on the View.
        /// </summary>
        private async Task ValidateHeader()
        {
            DebugHelper.Assert(this.kdbxReader != null);
            if (this.kdbxReader == null)
            {
                throw new InvalidOperationException("Cannot validate KDBX header if there is no reader instance");
            }

            try
            {
                if (CandidateFile == null)
                {
                    ParseResult = null;
                }
                else
                {
                    using (IRandomAccessStream fileStream = await CandidateFile.GetRandomReadAccessStreamAsync())
                    {
                        CancellationTokenSource cts = new CancellationTokenSource(5000);
                        ParseResult = await this.kdbxReader.ReadHeaderAsync(fileStream, cts.Token);
                    }
                }
            }
            catch (COMException)
            {
                // In the Windows 8.1 preview, opening a stream to a SkyDrive file can fail with no workaround.
                ParseResult = new ReaderResult(KdbxParserCode.UnableToReadFile);
            }
            finally
            {
                RaiseHeaderValidated();
                UnlockCommand.RaiseCanExecuteChanged();
                UseSavedCredentialsCommand.RaiseCanExecuteChanged();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Deserializes this node by using the <see cref="KdbxMetadata"/> binary collection
        /// to dereference @Ref.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="metadata">Used to dereference the Ref attribute.</param>
        /// <param name="parameters"></param>
        public KdbxBinAttachment(XElement xml, KdbxMetadata metadata, KdbxSerializationParameters parameters)
            : base(xml)
        {
            FileName = GetString("Key", true);

            XElement valueNode = GetNode("Value");

            if (valueNode == null)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Node {rootName} missing required child Value")
                          );
            }

            int    refId;
            string refAttr = valueNode.Attribute("Ref")?.Value;

            if (refAttr == null || !int.TryParse(refAttr, out refId))
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Child Value node of {rootName} missing required int @Ref")
                          );
            }

            Data = metadata.Binaries.GetById(refId);
            this.binaryCollection = metadata.Binaries;
        }
Beispiel #4
0
 public static Writer <Out, Reader <E, V> > SelectMany <Out, E, T, U, V>(
     this Writer <Out, T> self,
     Func <T, Reader <E, U> > bind,
     Func <T, U, V> project
     )
 {
     if (bind == null)
     {
         throw new ArgumentNullException(nameof(bind));
     }
     if (project == null)
     {
         throw new ArgumentNullException(nameof(project));
     }
     return(() =>
     {
         var resT = self.Valid()();
         if (resT.IsBottom)
         {
             return WriterResult.Bottom <Out, Reader <E, V> >(resT.Output);
         }
         return WriterResult.Return <Out, Reader <E, V> >(env =>
         {
             var resU = bind(resT.Value).Valid()(env);
             if (resU.IsBottom)
             {
                 return ReaderResult.Bottom <V>();
             }
             return ReaderResult.Return(project(resT.Value, resU.Value));
         }, resT.Output);
     });
 }
Beispiel #5
0
        /// <summary>
        /// Execution action for the UseSavedCredentials - attempts to unlock the document file
        /// using stored credentials after verifying the user's identity.
        /// </summary>
        private async Task DoUnlockWithSavedCredentials()
        {
            Task <bool> verificationTask = this.identityService.VerifyIdentityAsync();

            this.taskNotificationService.PushOperation(verificationTask, AsyncOperationType.IdentityVerification);

            if (!await verificationTask)
            {
                ParseResult = new ReaderResult(KdbxParserCode.CouldNotVerifyIdentity);
                return;
            }

            Task <IBuffer> credentialTask = this.credentialProvider.GetRawKeyAsync(CandidateFile.File);

            this.taskNotificationService.PushOperation(credentialTask, AsyncOperationType.CredentialVaultAccess);

            IBuffer storedCredential = await credentialTask;

            if (storedCredential == null)
            {
                ParseResult = new ReaderResult(KdbxParserCode.CouldNotRetrieveCredentials);
                return;
            }

            Task unlockTask = DoUnlockAsync(storedCredential);

            this.taskNotificationService.PushOperation(unlockTask, AsyncOperationType.DatabaseDecryption);

            await unlockTask;
        }
Beispiel #6
0
        public KdbxPart(XElement element)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }

            // We should only be parsing expected elements
            if (element.Name != rootName)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure(
                              $"KdbxPart parse mismatch - expected root node {rootName}, got {element.Name}"
                              )
                          );
            }

            // Build up a list of child elements to parse later
            this._rootNode = element;
            this._pristine = new Dictionary <string, IList <XElement> >();
            foreach (XElement node in element.Elements())
            {
                string key = node.Name.ToString();
                if (this._pristine.ContainsKey(key))
                {
                    this._pristine[key].Add(node);
                }
                else
                {
                    this._pristine[key] = new List <XElement> {
                        node
                    };
                }
            }
        }
Beispiel #7
0
 public static State <S, Reader <E, V> > SelectMany <S, E, T, U, V>(
     this State <S, T> self,
     Func <T, Reader <E, U> > bind,
     Func <T, U, V> project
     )
 {
     if (bind == null)
     {
         throw new ArgumentNullException(nameof(bind));
     }
     if (project == null)
     {
         throw new ArgumentNullException(nameof(project));
     }
     return((S s) =>
     {
         var resT = self.Valid()(s);
         if (resT.IsBottom)
         {
             return StateResult.Bottom <S, Reader <E, V> >(s);
         }
         return StateResult.Return <S, Reader <E, V> >(resT.State, envInner =>
         {
             var resU = bind(resT.Value).Valid()(envInner);
             if (resU.IsBottom)
             {
                 return new ReaderResult <V>(default(V), true);
             }
             return ReaderResult.Return(project(resT.Value, resU.Value));
         });
     });
 }
Beispiel #8
0
        public string GetString(string name, bool required = false)
        {
            DebugHelper.Assert(!string.IsNullOrEmpty(name));
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name cannot be null or empty", nameof(name));
            }

            XElement child = GetNode(name);

            if (child == null)
            {
                if (!required)
                {
                    return(null);
                }
                else
                {
                    throw new KdbxParseException(
                              ReaderResult.FromXmlParseFailure($"Node {rootName} missing required string child {name}")
                              );
                }
            }

            return(child.Value ?? string.Empty);
        }
Beispiel #9
0
        public Color?GetNullableColor(string name)
        {
            string cString = GetString(name);

            if (cString == null || cString.Length != 7 || cString[0] != '#')
            {
                return(null);
            }

            string rr = cString.Substring(1, 2);
            string gg = cString.Substring(3, 2);
            string bb = cString.Substring(5, 2);

            try
            {
                byte red   = byte.Parse(rr, NumberStyles.HexNumber);
                byte green = byte.Parse(gg, NumberStyles.HexNumber);
                byte blue  = byte.Parse(bb, NumberStyles.HexNumber);

                return(Color.FromArgb(0xFF, red, green, blue));
            }
            catch (FormatException)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Could not parse {rootName}'s color child {name} - value: {cString}")
                          );
            }
        }
        /// <summary>
        /// Initializes the design data.
        /// </summary>
        public DesignDatabaseUnlockViewModel()
        {
            CandidateFile = new MockDatabaseCandidate
            {
                FileName     = "My Database.kdbx",
                LastModified = new DateTimeOffset(DateTime.UtcNow),
                Size         = 12345,
            };

            Password = "******";

            UnlockCommand = new AsyncActionCommand(
                () => HasGoodHeader,
                () => Task.CompletedTask
                );

            UseSavedCredentialsCommand = new AsyncActionCommand(
                () => true,
                () => Task.CompletedTask
                );

            HasGoodHeader    = true;
            ParseResult      = new ReaderResult(KdbxParserCode.Success);
            RememberDatabase = true;
        }
Beispiel #11
0
 /// <summary>
 /// Validates that the specified enum value is defined in the provided enum.
 /// </summary>
 /// <typeparam name="T">An enum type to validate against.</typeparam>
 /// <param name="field">The header field to validated.</param>
 /// <param name="value">The enum value to validate.</param>
 private void RequireEnumDefined <T>(InnerHeaderField field, T value)
     where T : struct
 {
     if (!Enum.IsDefined(typeof(T), value))
     {
         throw new KdbxParseException(ReaderResult.FromHeaderDataUnknown(field, value.ToString()));
     }
 }
Beispiel #12
0
 public static Reader <Env, Env> Fold <Env, A>(this Reader <Env, A> self, Func <Env, A, Env> f) =>
 env =>
 {
     var resA = self(env);
     return(resA.IsFaulted
             ? ReaderResult <Env> .New(resA.ErrorInt)
             : ReaderResult <Env> .New(f(env, resA.Value)));
 };
Beispiel #13
0
        /// <summary>
        /// Initializes the Exception with the specified ReaderResult.
        /// </summary>
        /// <param name="error">The ReaderResult causing this Exception.</param>
        public KdbxParseException(ReaderResult error)
        {
            if (!error.IsError)
            {
                throw new ArgumentException("The provided ReaderResult is not an error.", "error");
            }

            Error = error;
        }
Beispiel #14
0
        /// <summary>
        /// Validates that the specified header field has a size matching a provided requirement. Throws on failure.
        /// </summary>
        /// <param name="field">The header field to validate.</param>
        /// <param name="size">The size of the data field.</param>
        /// <param name="requirement">An evaluator function that returns whether the size is valid.</param>
        /// <param name="explanation">A String explanation of the requirement.</param>
        private void RequireFieldDataSize(InnerHeaderField field, uint size, Predicate <uint> requirement, string explanation)
        {
            bool result = requirement(size);

            if (result)
            {
                return;
            }

            throw new KdbxParseException(ReaderResult.FromHeaderDataSize(field, size, explanation));
        }
        public IActionResult Initialize([FromBody] string payload)
        {
            try {
                var request = JsonDocument.Parse(payload).RootElement;

                var id      = request.GetProperty("Id").GetInt32();
                var version = request.GetProperty("Version").GetString();

                DbResult result;

                using (var db = new AccessControlDatabase()) {
                    var sql = @"
						SELECT 
							r.name,
							r.timeout,
							r.enabled,
							g.name AS groupName,
							r.settings
						FROM
							reader r
							INNER JOIN `group` g
								ON r.group_id = g.group_id
						WHERE
							r.reader_id = @0
						LIMIT 1;"                        ;

                    result = db.SingleOrDefault <DbResult>(sql, id);
                }

                if (id < 1 || result == null)
                {
                    return(StatusCode(401));
                }

                var clientAddress = HttpContext.Connection.RemoteIpAddress.ToString();

                RecordClient(id, clientAddress, version, payload);

                var output = new ReaderResult {
                    Name     = result.name,
                    Timeout  = result.timeout,
                    Enabled  = result.enabled,
                    Group    = result.groupName,
                    Settings = result.settings,
                };

                return(new JsonResult(output));
            }
            catch (Exception ex) {
                Console.Write(ex.ToString());

                return(StatusCode(500));
            }
        }
Beispiel #16
0
 private static ReaderResult <Unit> bmap <T>(ReaderResult <T> r, Action <T> f)
 {
     if (r.IsBottom)
     {
         return(Bottom <Unit>());
     }
     else
     {
         f(r.Value);
         return(Return(unit));
     }
 }
Beispiel #17
0
        public IActionResult Lookup(string id)
        {
            try {
                DbResult result;

                using (var db = new AccessControlDatabase()) {
                    var sql = @"
						SELECT 
							r.name,
							r.timeout,
							r.enabled,
							g.name AS groupName,
							r.address
						FROM
							reader r
							INNER JOIN `group` g
								ON r.group_id = g.group_id
						WHERE
							r.reader_id = @0
						LIMIT 1;"                        ;

                    result = db.SingleOrDefault <DbResult>(sql, id);
                }

                if (result == null)
                {
                    return(StatusCode(403));
                }

                var clientAddress = HttpContext.Connection.RemoteIpAddress.ToString();

                if (result.address != clientAddress)
                {
                    RecordClientAddress(id, clientAddress);
                }

                var output = new ReaderResult {
                    Name    = result.name,
                    Timeout = result.timeout,
                    Enabled = result.enabled,
                    Group   = result.groupName,
                };

                return(new JsonResult(output));
            }
            catch {
                return(StatusCode(500));
            }
        }
Beispiel #18
0
        public bool GetBool(string name)
        {
            bool?nullableB = GetNullableBool(name, true);

            if (nullableB.HasValue)
            {
                return(nullableB.Value);
            }
            else
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Node {rootName} missing required bool child {name}")
                          );
            }
        }
Beispiel #19
0
        /// <summary>
        /// Parses a collection of binaries from the given XML.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="parameters"></param>
        public KdbxBinaries(XElement xml, KdbxSerializationParameters parameters)
            : base(xml)
        {
            this.binaries = new SortedDictionary <int, KdbxBinary>();

            foreach (XElement ele in GetNodes(KdbxBinary.RootName))
            {
                KdbxBinary bin = new KdbxBinary(ele, parameters);
                if (this.binaries.ContainsKey(bin.Id))
                {
                    throw new KdbxParseException(
                              ReaderResult.FromXmlParseFailure($"Duplicate binary key {bin.Id}")
                              );
                }

                this.binaries.Add(bin.Id, bin);
            }
        }
Beispiel #20
0
 /// <summary>
 /// Runs the Reader monad and memoizes the result in a TryOption monad.  Use
 /// Match, IfSucc, IfNone, etc to extract.
 /// </summary>
 public static ReaderResult <A> Run <Env, A>(this Reader <Env, A> self, Env env)
 {
     try
     {
         if (self == null)
         {
             throw new ArgumentNullException(nameof(self));
         }
         if (env == null)
         {
             throw new ArgumentNullException(nameof(env));
         }
         return(self(env));
     }
     catch (Exception e)
     {
         return(ReaderResult <A> .New(Error.New(e)));
     }
 }
Beispiel #21
0
        public int GetInt(string name, int?def = null)
        {
            string iString = GetString(name, !def.HasValue);

            if (iString == null)
            {
                iString = def.Value.ToString();
            }

            int i;

            if (int.TryParse(iString, out i))
            {
                return(i);
            }
            else
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Could not parse {rootName}'s int child {name} - value: {iString}")
                          );
            }
        }
Beispiel #22
0
        /// <summary>
        /// Parses a KeePass document from the specified XML.
        /// </summary>
        /// <param name="xml">XML to deserialize.</param>
        /// <param name="headerBinaries">Any binaries that were parsed from a header.</param>
        /// <param name="rng">RNG used to encrypt protected strings.</param>
        /// <param name="parameters">Parameters controlling serialization.</param>
        public KdbxDocument(XElement xml, IEnumerable <ProtectedBinary> headerBinaries, IRandomNumberGenerator rng, KdbxSerializationParameters parameters)
            : base(xml)
        {
            XElement metadata = GetNode(KdbxMetadata.RootName);

            if (metadata == null)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Document has no {KdbxMetadata.RootName} node")
                          );
            }
            Metadata = new KdbxMetadata(metadata, headerBinaries, parameters);

            XElement root = GetNode(KdbxRoot.RootName);

            if (root == null)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Document has no {KdbxRoot.RootName} node")
                          );
            }
            Root = new KdbxRoot(root, rng, Metadata, parameters);
        }
Beispiel #23
0
        private void backgroundReader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ReaderResult result = (ReaderResult)e.Result;

            if (result.Status == ReaderResult.ReaderStatus.ReaderError)
            {
                MessageBox.Show(result.Message, Properties.Resources.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            btConnect.Tag       = true;
            btConnect.Text      = currentTranslation.btConnectText;
            btConnect.BackColor = Color.LimeGreen;

            if (calibRequest)
            {
                calibRequest = false;
                btCalib.PerformClick();
            }
            else
            {
                indicatorWorker.CancelAsync();
            }
        }
Beispiel #24
0
 internal static Reader <Env, T> Valid <Env, T>(this Reader <Env, T> self) =>
 self ?? (_ => ReaderResult.Bottom <T>());
Beispiel #25
0
 private static ReaderResult <T> Bottom <T>() =>
 ReaderResult.Bottom <T>();
Beispiel #26
0
 private static ReaderResult <T> Return <T>(T value) =>
 ReaderResult.Return(value);
Beispiel #27
0
 private static ReaderResult <R> bmap <T, R>(ReaderResult <T> r, Func <T, R> f) =>
 r.IsBottom
         ? Bottom <R>()
         : Return(f(r.Value));
Beispiel #28
0
        private static async Task <Dictionary <string /*Table0..N*/, ReaderResult> > ProcessExecQueryAsync(CancellationToken cancellationToken, SqlCommand cmd, Dictionary <string, string> inputParameters)
        {
            var reader = await cmd.ExecuteReaderAsync(cancellationToken);

            int resultIx      = 0;
            var allResultSets = new Dictionary <string, ReaderResult>();

            var limitToFields = ProcssSelectInstruction(inputParameters);

            do
            {
                var readerResult = new ReaderResult();

                allResultSets.Add($"Table{resultIx}", readerResult);

                var fieldTypes = Enumerable.Range(0, reader.FieldCount).Select(reader.GetFieldType).ToArray();

                //?var hasGeoType = fieldTypes.Contains(typeof(SqlGeography)) || fieldTypes.Contains(typeof(SqlGeometry));

                var allFieldNamesUpper = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).Select(n => n.ToUpper()).ToList();

                int fieldCount = reader.FieldCount;

                var fieldMappingIx = new List <int>();

                // if there exists a select list
                if (limitToFields?.ContainsKey(resultIx) ?? false)
                {
                    foreach (var limit in limitToFields[resultIx])
                    {
                        var ix = allFieldNamesUpper.IndexOf(limit);

                        if (ix >= 0)
                        {
                            fieldMappingIx.Add(ix);
                        }
                    }
                }
                else
                {
                    // default to ALL available fields
                    fieldMappingIx = Enumerable.Range(0, reader.FieldCount).ToList();
                }

                fieldCount = fieldMappingIx.Count;

                readerResult.Fields = Enumerable.Range(0, fieldCount)
                                      .Select(i => new DataField(reader.GetName(fieldMappingIx[i]), ToJqxType(reader.GetFieldType(fieldMappingIx[i]))))
                                      .ToArray();

                readerResult.Data = new List <object[]>();


                while (await reader.ReadAsync())
                {
                    // TODO: Cannot use GetValues as SqlGeography types currently throw as .NET Core cannot deserialize it properly. If SqlClient adds support review in future for possible perf benefit - fetch all rows at once instead of one by one. Also just consider the a $select instruction comes through (thus only asking for a subset of the columns)
                    // TODO: We can also possible split it like the below snippet - only take perf hit if we know a geo type is coming up
                    // if (!hasGeoType)
                    // {
                    //     var fullDataRow = new object[reader.FieldCount];// has to be all fields

                    //     // TODO: Handle $select
                    //     // TODO: What about Bytes?

                    //     reader.GetValues(fullDataRow);
                    //     readerResult.Data.Add(fullDataRow);
                    //     continue;
                    // }

                    var data = new object[fieldCount];

                    for (var dstIx = 0; dstIx < fieldCount; dstIx++)
                    {
                        var srcIx    = fieldMappingIx[dstIx];
                        var isDBNull = await reader.IsDBNullAsync(srcIx, cancellationToken);

                        if (isDBNull)
                        {
                            continue;
                        }

                        if (fieldTypes[srcIx] == typeof(byte[]))
                        {
                            var bytes = reader.GetSqlBytes(srcIx).Value;
                            data[dstIx] = Convert.ToBase64String(bytes);
                        }
                        else if (fieldTypes[srcIx] == typeof(SqlGeography))
                        {
                            var geometryReader = new NetTopologySuite.IO.SqlServerBytesReader {
                                IsGeography = true
                            };
                            var bytes    = reader.GetSqlBytes(srcIx).Value;
                            var geometry = geometryReader.Read(bytes);

                            var point = geometry as NetTopologySuite.Geometries.Point;

                            if (point != null)
                            {
                                data[dstIx] = new { lat = point.Y, lng = point.X };
                            }
                            else
                            {
                                data[dstIx] = geometry.ToString();
                            }
                        }
                        else
                        {
                            //var x = reader.GetProviderSpecificValue(colIx);
                            data[dstIx] = reader.GetValue(srcIx);
                        }
                    } // for each column

                    readerResult.Data.Add(data);
                }

                resultIx++;
            }while (await reader.NextResultAsync());

            return(allResultSets);
        }
Beispiel #29
0
        /// <summary>
        /// Attempts to unlock the document file.
        /// </summary>
        /// <param name="storedCredential">The key to use for decryption - if null, the ViewModel's
        /// credentials are used instead.</param>
        private async Task DoUnlockAsync(IBuffer storedCredential)
        {
            DebugHelper.Assert(CanUnlock());
            if (!CanUnlock())
            {
                throw new InvalidOperationException("The ViewModel is not in a state that can unlock the database!");
            }

            CancellationTokenSource cts = new CancellationTokenSource();

            try
            {
                using (IRandomAccessStream stream = await CandidateFile.GetRandomReadAccessStreamAsync())
                {
                    Task <KdbxDecryptionResult> decryptionTask;
                    if (storedCredential != null)
                    {
                        decryptionTask = this.kdbxReader.DecryptFile(stream, storedCredential, cts.Token);
                    }
                    else
                    {
                        decryptionTask = this.kdbxReader.DecryptFileAsync(stream, Password, KeyFile, cts.Token);
                    }

                    if (this.taskNotificationService.CurrentTask == null || this.taskNotificationService.CurrentTask.IsCompleted)
                    {
                        this.taskNotificationService.PushOperation(decryptionTask, cts, AsyncOperationType.DatabaseDecryption);
                    }
                    KdbxDecryptionResult result = await decryptionTask;

                    ParseResult = result.Result;

                    DebugHelper.Trace($"Got ParseResult from database unlock attempt: {ParseResult}");
                    if (!ParseResult.IsError)
                    {
                        // The database candidate to proceed into the next stage with
                        IDatabaseCandidate candidateToUse = CandidateFile;

                        if (CacheDatabase)
                        {
                            // We do not use UseAppControlledDatabaseAsync here because it has extra baggage.
                            // We don't need to refresh the view at this stage, just fire an event using
                            // the cached file.
                            candidateToUse = await GetCachedCandidateAsync();
                        }
                        if (RememberDatabase)
                        {
                            string accessToken = this.futureAccessList.Add(candidateToUse.File, candidateToUse.FileName);
                            DebugHelper.Trace($"Unlock was successful and database was remembered with token: {accessToken}");
                        }
                        else
                        {
                            DebugHelper.Trace("Unlock was successful but user opted not to remember the database.");
                        }

                        if (SaveCredentials)
                        {
                            bool storeCredential = false;

                            // If we were not already using a stored credential, we need user
                            // consent to continue.
                            if (storedCredential == null)
                            {
                                Task <bool> identityTask = this.identityService.VerifyIdentityAsync();
                                if (this.taskNotificationService.CurrentTask == null || this.taskNotificationService.CurrentTask.IsCompleted)
                                {
                                    this.taskNotificationService.PushOperation(identityTask, AsyncOperationType.IdentityVerification);
                                }

                                storeCredential  = await identityTask;
                                storedCredential = result.GetRawKey();
                            }
                            else
                            {
                                // If we have a stored credential, we already got consent.
                                storeCredential = true;
                            }

                            if (storeCredential)
                            {
                                if (!await this.credentialProvider.TryStoreRawKeyAsync(candidateToUse.File, storedCredential))
                                {
                                    EventHandler <CredentialStorageFailureEventArgs> handler = CredentialStorageFailed;
                                    if (handler != null)
                                    {
                                        // If we could not store a credential, give the View a chance to try again.
                                        CredentialStorageFailureEventArgs eventArgs =
                                            new CredentialStorageFailureEventArgs(
                                                this.credentialProvider,
                                                this.credentialViewModelFactory,
                                                candidateToUse,
                                                storedCredential
                                                );

                                        handler(this, eventArgs);
                                        await eventArgs.DeferAsync();
                                    }
                                }
                            }
                        }

                        await RaiseDocumentReady(result.GetDocument(), candidateToUse);
                    }
                }
            }
            catch (COMException)
            {
                // In the Windows 8.1 preview, opening a stream to a SkyDrive file can fail with no workaround.
                ParseResult = new ReaderResult(KdbxParserCode.UnableToReadFile);
            }
        }
Beispiel #30
0
        /// <summary>
        /// Decodes an instance from serialized XML.
        /// </summary>
        /// <param name="xml">The XML to deserialize.</param>
        /// <param name="parameters">Parameters controlling serialization.</param>
        public KdbxBinary(XElement xml, KdbxSerializationParameters parameters)
        {
            // Parse out int ID attribute
            string idAttr = xml?.Attribute("ID")?.Value;

            if (idAttr == null)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"KdbxBinary was missing required ID attribute")
                          );
            }

            if (!Int32.TryParse(idAttr, out int id))
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"KdbxBinary ID attribute could not be parsed into an int")
                          );
            }

            Id = id;

            // Parse out bool Compressed attribute
            string compressAttr = xml?.Attribute("Compressed")?.Value ?? "false";

            if (!Boolean.TryParse(compressAttr, out bool compressed))
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"KdbxBinary Compressed attribute could not be parsed into a bool")
                          );
            }

            // Parse base64-encoded content
            byte[] content;
            try
            {
                content = CryptographicBuffer.DecodeFromBase64String(xml?.Value)?.ToArray();
                if (content == null)
                {
                    content = new byte[0];
                }
            }
            catch (Exception)
            {
                throw new KdbxParseException(
                          ReaderResult.FromXmlParseFailure($"Could not decode KdbxBinary content as base64 data")
                          );
            }

            // Decompress content if needed
            if (compressed && content.Length > 0)
            {
                byte[] decompressed;
                using (Stream memStream = new MemoryStream(content))
                {
                    using (Stream gzipStream = new GZipStream(memStream, CompressionMode.Decompress))
                    {
                        byte[]      buffer = new byte[1024];
                        int         read   = gzipStream.Read(buffer, 0, buffer.Length);
                        List <byte> bytes  = new List <byte>();
                        while (read > 0)
                        {
                            bytes.AddRange(buffer.Take(read));
                            read = gzipStream.Read(buffer, 0, buffer.Length);
                        }

                        decompressed = bytes.ToArray();
                    }
                }

                content = decompressed;
            }

            this.binaryData = new ProtectedBinary(content, false);
        }