Beispiel #1
0
        internal SharedFolder(SyncDownSharedFolder sf)
        {
            Uid                  = sf.sharedFolderUid;
            Name                 = Encoding.UTF8.GetString(CryptoUtils.DecryptAesV1(sf.name.Base64UrlDecode(), sf.unencryptedSharedFolderKey));
            ManageRecords        = sf.manageRecords ?? DefaultManageRecords;
            ManageUsers          = sf.manageUsers ?? DefaultManageUsers;
            DefaultManageRecords = sf.defaultManageRecords;
            DefaultManageUsers   = sf.defaultManageUsers;
            DefaultCanEdit       = sf.defaultCanEdit;
            DefaultCanShare      = sf.defaultCanShare;
            if (sf.records != null)
            {
                foreach (var r in sf.records)
                {
                    Records.Add(new SharedFolderRecord
                    {
                        RecordUid = r.recordUid,
                        CanEdit   = r.canEdit,
                        CanShare  = r.canShare
                    });
                }
            }

            if (sf.users != null)
            {
                foreach (var u in sf.users)
                {
                    Users.Add(new SharedFolderUser
                    {
                        Username      = u.username,
                        ManageRecords = u.manageRecords,
                        ManageUsers   = u.manageUsers
                    });
                }
            }

            if (sf.teams != null)
            {
                foreach (var t in sf.teams)
                {
                    Teams.Add(new SharedFolderTeam
                    {
                        TeamUid       = t.teamUid,
                        Name          = t.name,
                        ManageRecords = t.manageRecords,
                        ManageUsers   = t.manageUsers
                    });
                }
            }
        }
Beispiel #2
0
        private static void ProcessSubFolders(this Vault vault, SyncDownResponse rs)
        {
            var comparers  = new Comparers();
            var folderList = new SortedSet <IFolderNode>(vault.userFolders.Values, comparers);
            var recordList = new SortedSet <IRecordNode>(vault.userFolderRecords ?? Enumerable.Empty <IRecordNode>(), comparers);

            if (rs.userFoldersRemoved != null)
            {
                foreach (var ufr in rs.userFoldersRemoved)
                {
                    folderList.RemoveWhere(x => x.FolderUid == ufr.folderUid);
                    recordList.RemoveWhere(x => x.FolderUid == ufr.folderUid);
                }
            }

            if (rs.sharedFolderFolderRemoved != null)
            {
                foreach (var sffr in rs.sharedFolderFolderRemoved)
                {
                    folderList.RemoveWhere(x => x.FolderUid == sffr.folderUid);
                    recordList.RemoveWhere(x => x.FolderUid == sffr.folderUid);
                }
            }

            if (rs.userFolderSharedFoldersRemoved != null)
            {
                foreach (var ufsfr in rs.userFolderSharedFoldersRemoved)
                {
                    folderList.RemoveWhere(x => x.FolderUid == ufsfr.folderUid);
                    recordList.RemoveWhere(x => x.FolderUid == ufsfr.folderUid);
                }
            }

            if (rs.userFoldersRemovedRecords != null)
            {
                foreach (var uffr in rs.userFoldersRemovedRecords)
                {
                    recordList.Remove(uffr);
                }
            }

            if (rs.sharedFolderFolderRecordsRemoved != null)
            {
                foreach (var sffrr in rs.sharedFolderFolderRecordsRemoved)
                {
                    recordList.Remove(sffrr);
                }
            }

            if (rs.userFolders != null)
            {
                foreach (var uf in rs.userFolders)
                {
                    var encryptedKey = uf.userFolderKey.Base64UrlDecode();
                    uf.unencryptedFolderKey = uf.keyType == 2
                        ? CryptoUtils.DecryptRsa(encryptedKey, vault.Auth.PrivateKey)
                        : CryptoUtils.DecryptAesV1(encryptedKey, vault.Auth.DataKey);
                    folderList.Remove(uf);
                    folderList.Add(uf);
                }
            }

            if (rs.sharedFolderFolders != null)
            {
                foreach (var sff in rs.sharedFolderFolders)
                {
                    if (vault.sharedFolders.TryGetValue(sff.sharedFolderUid, out SyncDownSharedFolder sf))
                    {
                        var encryptedKey = sff.sharedFolderFolderKey.Base64UrlDecode();
                        sff.unencryptedFolderKey = CryptoUtils.DecryptAesV1(encryptedKey, sf.unencryptedSharedFolderKey);
                        folderList.Remove(sff);
                        folderList.Add(sff);
                    }
                    else
                    {
                        Trace.TraceError("Sync_Down: shared_folder_folders: Shared Folder UID {0} not found", sff.sharedFolderUid);
                    }
                }
            }

            if (rs.userFolderSharedFolders != null)
            {
                foreach (var ufsf in rs.userFolderSharedFolders)
                {
                    folderList.Remove(ufsf);
                    folderList.Add(ufsf);
                }
            }

            if (rs.userFolderRecords != null)
            {
                foreach (var ufr in rs.userFolderRecords)
                {
                    recordList.Add(ufr);
                }
            }

            if (rs.sharedFolderFolderRecords != null)
            {
                foreach (var sffr in rs.sharedFolderFolderRecords)
                {
                    recordList.Add(sffr);
                }
            }

            var toDelete = new HashSet <string>();

            foreach (var folder in vault.keeperFolders.Values)
            {
                toDelete.Add(folder.FolderUid);
                folder.Children.Clear();
                folder.Records.Clear();
            }
            foreach (var folder in folderList)
            {
                if (vault.keeperFolders.TryGetValue(folder.FolderUid, out FolderNode node))
                {
                    toDelete.Remove(folder.FolderUid);
                    node.Children.Clear();
                    node.Records.Clear();
                    node.Name = null;
                }
                else
                {
                    node = new FolderNode
                    {
                        FolderType = folder.Type,
                        FolderUid  = folder.FolderUid
                    };
                    vault.keeperFolders.Add(folder.FolderUid, node);
                }
                node.ParentUid = folder.ParentUid;

                byte[] unencrypted_data = null;
                switch (folder.Type)
                {
                case FolderType.UserFolder:
                    if (folder is SyncDownUserFolder uf)
                    {
                        unencrypted_data = CryptoUtils.DecryptAesV1(uf.data.Base64UrlDecode(), uf.unencryptedFolderKey);
                    }
                    else
                    {
                        Trace.TraceError("Folder UID {0} expected to be User-Folder", folder.FolderUid);
                    }
                    break;

                case FolderType.SharedFolderForder:
                    if (folder is SyncDownSharedFolderFolder sff)
                    {
                        unencrypted_data = CryptoUtils.DecryptAesV1(sff.data.Base64UrlDecode(), sff.unencryptedFolderKey);
                    }
                    else
                    {
                        Trace.TraceError("Folder UID {0} expected to be Shared-Folder-Folder", folder.FolderUid);
                    }
                    break;

                case FolderType.SharedFolder:
                    if (vault.sharedFolders.TryGetValue(folder.FolderUid, out SyncDownSharedFolder sf))
                    {
                        node.Name = Encoding.UTF8.GetString(CryptoUtils.DecryptAesV1(sf.name.Base64UrlDecode(), sf.unencryptedSharedFolderKey));
                    }
                    else
                    {
                        Trace.TraceError("Folder UID {0} expected to be Shared-Folder", folder.FolderUid);
                    }
                    break;
                }
                if (unencrypted_data != null)
                {
                    var serializer = new DataContractJsonSerializer(typeof(FolderData));
                    using (var stream = new MemoryStream(unencrypted_data))
                    {
                        var folderData = serializer.ReadObject(stream) as FolderData;
                        node.Name = folderData.name;
                    }
                }
                if (string.IsNullOrEmpty(node.Name))
                {
                    node.Name = node.FolderUid;
                }
            }
            foreach (var uid in toDelete)
            {
                vault.keeperFolders.Remove(uid);
            }
            vault.Root.Children.Clear();
            vault.Root.Records.Clear();

            foreach (var node in vault.keeperFolders.Values)
            {
                if (string.IsNullOrEmpty(node.ParentUid))
                {
                    vault.Root.Children.Add(node.FolderUid);
                }
                else
                {
                    if (vault.keeperFolders.TryGetValue(node.ParentUid, out FolderNode parent))
                    {
                        parent.Children.Add(node.FolderUid);
                    }
                    else
                    {
                        Trace.TraceError("Folder UID {0} was lost", node.FolderUid);
                    }
                }
            }

            foreach (var record in recordList)
            {
                if (string.IsNullOrEmpty(record.FolderUid))
                {
                    vault.Root.Records.Add(record.RecordUid);
                }
                else
                {
                    if (vault.keeperFolders.TryGetValue(record.FolderUid, out FolderNode node))
                    {
                        node.Records.Add(record.RecordUid);
                    }
                    else
                    {
                        Trace.TraceError("Folder UID {0} was lost", node.FolderUid);
                        vault.Root.Records.Add(record.RecordUid);
                    }
                }
            }

            vault.userFolders.Clear();
            foreach (var folder in folderList)
            {
                vault.userFolders.Add(folder.FolderUid, folder);
            }
            vault.userFolderRecords = recordList.ToList();
        }
Beispiel #3
0
        internal static void DecryptRecords(this Vault vault)
        {
            var uids = new HashSet <string>();

            uids.UnionWith(vault.records.Keys);
            uids.ExceptWith(vault.keeperRecords.Keys);
            if (uids.Count > 0)
            {
                var dataSerializer  = new DataContractJsonSerializer(typeof(RecordData));
                var extraSerializer = new DataContractJsonSerializer(typeof(RecordExtra));

                foreach (var uid in uids)
                {
                    if (vault.records.TryGetValue(uid, out SyncDownRecord sdr))
                    {
                        try
                        {
                            var record = new PasswordRecord(uid);

                            var unencrypted_data = CryptoUtils.DecryptAesV1(sdr.data.Base64UrlDecode(), sdr.unencryptedRecordKey);
                            using (var ms = new MemoryStream(unencrypted_data))
                            {
                                var data = (RecordData)dataSerializer.ReadObject(ms);
                                record.Title    = data.title;
                                record.Login    = data.secret1;
                                record.Password = data.secret2;
                                record.Link     = data.link;
                                record.Notes    = data.notes;
                                if (data.custom != null)
                                {
                                    foreach (var cr in data.custom)
                                    {
                                        record.Custom.Add(new CustomField
                                        {
                                            Name  = cr.name,
                                            Value = cr.value,
                                            Type  = cr.type
                                        });
                                    }
                                }
                            }

                            if (!string.IsNullOrEmpty(sdr.extra))
                            {
                                var unencrypted_extra = CryptoUtils.DecryptAesV1(sdr.extra.Base64UrlDecode(), sdr.unencryptedRecordKey);
                                using (var ms = new MemoryStream(unencrypted_extra))
                                {
                                    var extra = (RecordExtra)extraSerializer.ReadObject(ms);
                                    if (extra.files != null && extra.files.Length > 0)
                                    {
                                        foreach (var file in extra.files)
                                        {
                                            var atta = new AttachmentFile
                                            {
                                                Id           = file.id,
                                                Key          = file.key,
                                                Name         = file.name,
                                                Title        = file.title ?? "",
                                                Type         = file.type ?? "",
                                                Size         = file.size ?? 0,
                                                LastModified = file.lastModified != null?file.lastModified.Value.FromUnixTimeMilliseconds() : DateTimeOffset.Now
                                            };
                                            if (file.thumbs != null)
                                            {
                                                atta.Thumbnails = file.thumbs
                                                                  .Select(t => new AttachmentFileThumb
                                                {
                                                    Id   = t.id,
                                                    Type = t.type,
                                                    Size = t.size ?? 0
                                                })
                                                                  .ToArray();
                                            }
                                            record.Attachments.Add(atta);
                                        }
                                    }
                                }
                            }

                            vault.keeperRecords.Add(uid, record);
                        }
                        catch (Exception e)
                        {
                            Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", uid, e.GetType().Name, e.Message);
                        }
                    }
                }
            }
        }
Beispiel #4
0
        public static async Task SyncDown(this Vault vault)
        {
            var command = new SyncDownCommand
            {
                revision   = vault.Revision,
                include    = new string[] { "sfheaders", "sfrecords", "sfusers", "teams", "folders" },
                deviceName = KeeperEndpoint.DefaultDeviceName
            };

            var rs = await vault.Auth.ExecuteAuthCommand <SyncDownCommand, SyncDownResponse>(command);

            ISet <string> uids = new HashSet <string>();

            if (rs.fullSync)
            {
                vault.metaData.Clear();
                vault.records.Clear();
                vault.sharedFolders.Clear();
                vault.teams.Clear();

                vault.keeperFolders.Clear();
                vault.userFolderRecords = null;

                vault.keeperRecords.Clear();
            }

            vault.Revision = rs.revision;

            if (rs.removedRecords != null)
            {
                foreach (var uid in rs.removedRecords)
                {
                    vault.DeleteRecordKey(uid);
                    vault.metaData.Remove(uid);
                }
            }

            if (rs.removedTeams != null)
            {
                foreach (var teamUid in rs.removedTeams)
                {
                    vault.DeleteTeamKey(teamUid);
                    if (vault.teams.TryGetValue(teamUid, out SyncDownTeam sdt))
                    {
                        if (sdt.sharedFolderKeys != null)
                        {
                            foreach (var sfk in sdt.sharedFolderKeys)
                            {
                                if (vault.sharedFolders.TryGetValue(sfk.sharedFolderUid, out SyncDownSharedFolder sdsf))
                                {
                                    if (sdsf.teams != null)
                                    {
                                        sdsf.teams = sdsf.teams.Where(x => x.teamUid != teamUid).ToArray();
                                    }
                                }
                            }
                        }
                        vault.teams.Remove(teamUid);
                    }
                }
            }

            if (rs.removedSharedFolders != null)
            {
                foreach (var sharedFolderUid in rs.removedSharedFolders)
                {
                    vault.DeleteSharedFolderKey(sharedFolderUid);
                    if (vault.sharedFolders.TryGetValue(sharedFolderUid, out SyncDownSharedFolder sdsf))
                    {
                        sdsf.sharedFolderKey = null;
                        sdsf.keyType         = null;
                        if (sdsf.users != null)
                        {
                            sdsf.users = sdsf.users.Where(x => string.Compare(x.username, vault.Auth.Username, true) != 0).ToArray();
                        }
                    }
                }
            }

            if (rs.teams != null)
            {
                foreach (var t in rs.teams)
                {
                    if (vault.teams.TryGetValue(t.teamUid, out SyncDownTeam team))
                    {
                        if (t.removedSharedFolders != null)
                        {
                            uids.Clear();
                            uids.UnionWith(t.removedSharedFolders);
                            team.sharedFolderKeys = t.sharedFolderKeys.Where(x => uids.Contains(x.sharedFolderUid)).ToArray();
                        }
                        if (t.sharedFolderKeys != null)
                        {
                            if (team.sharedFolderKeys == null)
                            {
                                team.sharedFolderKeys = t.sharedFolderKeys;
                            }
                            else
                            {
                                team.sharedFolderKeys = team.sharedFolderKeys.Concat(t.sharedFolderKeys).ToArray();
                            }
                        }
                        team.name          = t.name ?? team.name;
                        team.restrictEdit  = t.restrictEdit;
                        team.restrictView  = t.restrictView;
                        team.restrictShare = t.restrictShare;
                    }
                    else
                    {
                        vault.teams.Add(t.teamUid, t);
                    }
                }
            }

            if (rs.sharedFolders != null)
            {
                foreach (var sf in rs.sharedFolders)
                {
                    if (sf.fullSync == true)
                    {
                        vault.sharedFolders.Remove(sf.sharedFolderUid);
                    }
                    if (vault.sharedFolders.TryGetValue(sf.sharedFolderUid, out SyncDownSharedFolder sharedFolder))
                    {
                        sharedFolder.revision      = sf.revision;
                        sharedFolder.manageRecords = sf.manageRecords ?? sharedFolder.manageRecords;
                        sharedFolder.manageUsers   = sf.manageUsers ?? sharedFolder.manageUsers;
                        sharedFolder.name          = sf.name ?? sharedFolder.name;

                        if (sf.recordsRemoved != null && sharedFolder.records != null)
                        {
                            uids.Clear();
                            uids.UnionWith(sf.recordsRemoved);
                            sharedFolder.records = sharedFolder.records.Where(x => !uids.Contains(x.recordUid)).ToArray();
                        }
                        if (sf.usersRemoved != null && sharedFolder.users != null)
                        {
                            uids.Clear();
                            uids.UnionWith(sf.usersRemoved);
                            sharedFolder.users = sharedFolder.users.Where(x => !uids.Contains(x.username)).ToArray();
                        }
                        if (sf.teamsRemoved != null && sharedFolder.teams != null)
                        {
                            uids.Clear();
                            uids.UnionWith(sf.teamsRemoved);
                            sharedFolder.teams = sharedFolder.teams.Where(x => !uids.Contains(x.teamUid)).ToArray();
                        }
                        if (sf.records != null)
                        {
                            if (sharedFolder.records != null)
                            {
                                sharedFolder.records = sharedFolder.records.Concat(sf.records).ToArray();
                            }
                            else
                            {
                                sharedFolder.records = sf.records;
                            }
                        }
                        if (sf.users != null)
                        {
                            if (sharedFolder.users != null)
                            {
                                sharedFolder.users = sharedFolder.users.Concat(sf.users).ToArray();
                            }
                            else
                            {
                                sharedFolder.users = sf.users;
                            }
                        }
                        if (sf.teams != null)
                        {
                            if (sharedFolder.teams != null)
                            {
                                sharedFolder.teams = sharedFolder.teams.Concat(sf.teams).ToArray();
                            }
                            else
                            {
                                sharedFolder.teams = sf.teams;
                            }
                        }
                    }
                    else
                    {
                        vault.sharedFolders.Add(sf.sharedFolderUid, sf);
                    }
                    vault.keeperSharedFolders.Remove(sf.sharedFolderUid);
                }
            }

            if (rs.recordMetaData != null)
            {
                foreach (var rmd in rs.recordMetaData)
                {
                    if (vault.metaData.TryGetValue(rmd.recordUid, out SyncDownRecordMetaData metaData))
                    {
                        metaData.recordKey     = rmd.recordKey;
                        metaData.recordKeyType = rmd.recordKeyType;
                        metaData.owner         = rmd.owner;
                        metaData.canEdit       = rmd.canEdit;
                        metaData.canShare      = rmd.canShare;
                    }
                    else
                    {
                        vault.metaData.Add(rmd.recordUid, rmd);
                    }
                }
            }

            if (rs.records != null)
            {
                foreach (var r in rs.records)
                {
                    if (vault.records.TryGetValue(r.recordUid, out SyncDownRecord record))
                    {
                        record.data  = r.data;
                        record.extra = r.extra;
                        record.udata = r.udata;
                        record.clientModifiedTime = r.clientModifiedTime;
                        record.revision           = r.revision;
                        record.version            = r.version;
                        record.shared             = r.shared;
                    }
                    else
                    {
                        vault.records.Add(r.recordUid, r);
                    }
                    vault.keeperRecords.Remove(r.recordUid);
                }
            }

            //Process keys
            foreach (var team in vault.teams.Values)
            {
                if (team.unencryptedTeamKey == null)
                {
                    byte[] teamKey = null;
                    try
                    {
                        if (team.teamKeyType == 1)
                        {
                            teamKey = CryptoUtils.DecryptAesV1(team.teamKey.Base64UrlDecode(), vault.Auth.DataKey);
                        }
                        else if (team.teamKeyType == 2)
                        {
                            teamKey = CryptoUtils.DecryptRsa(team.teamKey.Base64UrlDecode(), vault.Auth.PrivateKey);
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.TraceError("Decrypt Team Key: UID: {0}, {1}: \"{2}\"", team.teamUid, e.GetType().Name, e.Message);
                    }
                    if (teamKey != null)
                    {
                        team.unencryptedTeamKey = teamKey;
                    }
                }
            }

            foreach (var sharedFolder in vault.sharedFolders.Values)
            {
                if (sharedFolder.unencryptedSharedFolderKey == null)
                {
                    byte[] key = null;
                    if (string.IsNullOrEmpty(sharedFolder.sharedFolderKey))
                    {
                        if (sharedFolder.teams != null)
                        {
                            foreach (var team in sharedFolder.teams)
                            {
                                if (vault.teams.TryGetValue(team.teamUid, out SyncDownTeam sdt))
                                {
                                    if (sdt.sharedFolderKeys != null)
                                    {
                                        var sfk = sdt.sharedFolderKeys.FirstOrDefault(x => x.sharedFolderUid == sharedFolder.sharedFolderUid);
                                        if (sfk != null)
                                        {
                                            try
                                            {
                                                if (sfk.keyType == 1)
                                                {
                                                    key = CryptoUtils.DecryptAesV1(sfk.sharedFolderKey.Base64UrlDecode(), sdt.unencryptedTeamKey);
                                                }
                                                else if (sfk.keyType == 2)
                                                {
                                                    key = CryptoUtils.DecryptRsa(sfk.sharedFolderKey.Base64UrlDecode(), sdt.PrivateKey);
                                                }
                                            }
                                            catch (Exception e)
                                            {
                                                Trace.TraceError("Decrypt Shared Folder Key: UID: {0}, Team UID: {1}, {2}: \"{3}\"", sharedFolder.sharedFolderUid, sdt.teamUid, e.GetType().Name, e.Message);
                                            }
                                        }
                                    }
                                }
                                if (key != null)
                                {
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        try
                        {
                            if (sharedFolder.keyType == 1)
                            {
                                key = CryptoUtils.DecryptAesV1(sharedFolder.sharedFolderKey.Base64UrlDecode(), vault.Auth.DataKey);
                            }
                            else if (sharedFolder.keyType == 2)
                            {
                                key = CryptoUtils.DecryptRsa(sharedFolder.sharedFolderKey.Base64UrlDecode(), vault.Auth.PrivateKey);
                            }
                        }
                        catch (Exception e)
                        {
                            Trace.TraceError("Decrypt Shared Folder Key: UID: {0}, {1}: \"{2}\"", sharedFolder.sharedFolderUid, e.GetType().Name, e.Message);
                        }
                    }
                    if (key != null)
                    {
                        sharedFolder.unencryptedSharedFolderKey = key;
                    }
                }
            }

            uids.Clear();
            uids.UnionWith(vault.sharedFolders.Values.Where(x => x.unencryptedSharedFolderKey == null).Select(x => x.sharedFolderUid));
            foreach (var uid in uids)
            {
                vault.sharedFolders.Remove(uid);
            }

            foreach (var record in vault.records.Values)
            {
                if (record.unencryptedRecordKey == null)
                {
                    byte[] key = null;
                    if (vault.metaData.TryGetValue(record.recordUid, out SyncDownRecordMetaData sdrmd))
                    {
                        if (string.IsNullOrEmpty(sdrmd.recordKey))
                        {
                            key = vault.Auth.DataKey;
                        }
                        else
                        {
                            try
                            {
                                if (sdrmd.recordKeyType == 1)
                                {
                                    key = CryptoUtils.DecryptAesV1(sdrmd.recordKey.Base64UrlDecode(), vault.Auth.DataKey);
                                }
                                else if (sdrmd.recordKeyType == 2)
                                {
                                    key = CryptoUtils.DecryptRsa(sdrmd.recordKey.Base64UrlDecode(), vault.Auth.PrivateKey);
                                }
                            }
                            catch (Exception e)
                            {
                                Trace.TraceError("Decrypt Record Key: UID: {0}, {1}: \"{2}\"", record.recordUid, e.GetType().Name, e.Message);
                            }
                        }
                    }
                    else
                    {
                        foreach (var sharedFolder in vault.sharedFolders.Values)
                        {
                            if (sharedFolder.records != null)
                            {
                                var sfr = sharedFolder.records.FirstOrDefault(x => x.recordUid == record.recordUid);
                                if (sfr != null)
                                {
                                    try
                                    {
                                        key = CryptoUtils.DecryptAesV1(sfr.recordKey.Base64UrlDecode(), sharedFolder.unencryptedSharedFolderKey);
                                    }
                                    catch (Exception e)
                                    {
                                        Trace.TraceError("Decrypt Record Key: UID: {0}, Shared Folder UID: {1}, {2}: \"{3}\"", record.recordUid, sharedFolder.sharedFolderUid, e.GetType().Name, e.Message);
                                    }
                                }
                                if (key != null)
                                {
                                    break;
                                }
                            }
                        }
                    }
                    if (key != null)
                    {
                        record.unencryptedRecordKey = key;
                    }
                }
            }

            uids.Clear();
            uids.UnionWith(vault.records.Values.Where(x => x.unencryptedRecordKey == null).Select(x => x.recordUid));
            foreach (var uid in uids)
            {
                vault.records.Remove(uid);
            }

            uids.Clear();
            uids.UnionWith(vault.keeperRecords.Keys);
            uids.ExceptWith(vault.records.Keys);
            foreach (var uid in uids)
            {
                vault.keeperRecords.Remove(uid);
            }

            vault.DecryptRecords();

            uids.Clear();
            uids.UnionWith(vault.sharedFolders.Values.Where(x => x.unencryptedSharedFolderKey == null).Select(x => x.sharedFolderUid));
            foreach (var uid in uids)
            {
                vault.sharedFolders.Remove(uid);
            }

            uids.Clear();
            uids.UnionWith(vault.keeperSharedFolders.Keys);
            uids.ExceptWith(vault.sharedFolders.Keys);
            foreach (var uid in uids)
            {
                vault.keeperSharedFolders.Remove(uid);
            }
            vault.DecryptSharedFolders();

            vault.ProcessSubFolders(rs);
        }
Beispiel #5
0
        public async Task SaveRecord(PasswordRecord record, bool skipData = false, bool skipExtra = true)
        {
            SyncDownRecord existingRecord = null;

            if (!string.IsNullOrEmpty(record.Uid))
            {
                records.TryGetValue(record.Uid, out existingRecord);
            }
            var updateRecord = new RecordUpdateRecord();

            byte[] recordKey = null;
            if (existingRecord != null)
            {
                updateRecord.recordUid = existingRecord.recordUid;
                recordKey = existingRecord.unencryptedRecordKey;
                if (metaData.TryGetValue(existingRecord.recordUid, out SyncDownRecordMetaData sdrmd))
                {
                    if (sdrmd.recordKeyType == 2)
                    {
                        updateRecord.recordKey = CryptoUtils.EncryptAesV1(recordKey, Auth.DataKey).Base64UrlEncode();
                    }
                }
                updateRecord.revision = existingRecord.revision;
                ResolveRecordAccessPath(updateRecord);
            }
            else
            {
                updateRecord.recordUid = CryptoUtils.GenerateUid();
                recordKey = CryptoUtils.GenerateEncryptionKey();
                updateRecord.recordKey = CryptoUtils.EncryptAesV1(recordKey, Auth.DataKey).Base64UrlEncode();
                updateRecord.revision  = 0;
            }
            var settings = new DataContractJsonSerializerSettings
            {
                UseSimpleDictionaryFormat = true
            };

            if (!skipData)
            {
                var        dataSerializer = new DataContractJsonSerializer(typeof(RecordData), settings);
                RecordData existingData   = null;
                if (existingRecord != null)
                {
                    try
                    {
                        var unencrypted_data = CryptoUtils.DecryptAesV1(existingRecord.data.Base64UrlDecode(), existingRecord.unencryptedRecordKey);
                        using (var ms = new MemoryStream(unencrypted_data))
                        {
                            existingData = (RecordData)dataSerializer.ReadObject(ms);
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", existingRecord.recordUid, e.GetType().Name, e.Message);
                    }
                }
                var data = record.ExtractRecordData(existingData);
                using (var ms = new MemoryStream())
                {
                    dataSerializer.WriteObject(ms, data);
                    updateRecord.data = CryptoUtils.EncryptAesV1(ms.ToArray(), recordKey).Base64UrlEncode();
                }
            }
            if (!skipExtra)
            {
                var         extraSerializer = new DataContractJsonSerializer(typeof(RecordExtra), settings);
                RecordExtra existingExtra   = null;
                if (existingRecord != null)
                {
                    try
                    {
                        var unencrypted_extra = CryptoUtils.DecryptAesV1(existingRecord.extra.Base64UrlDecode(), existingRecord.unencryptedRecordKey);
                        using (var ms = new MemoryStream(unencrypted_extra))
                        {
                            existingExtra = (RecordExtra)extraSerializer.ReadObject(ms);
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", existingRecord.recordUid, e.GetType().Name, e.Message);
                    }
                }
                var extra = record.ExtractRecordExtra(existingExtra);
                using (var ms = new MemoryStream())
                {
                    extraSerializer.WriteObject(ms, extra);
                    updateRecord.extra = CryptoUtils.EncryptAesV1(ms.ToArray(), recordKey).Base64UrlEncode();
                }
                var udata = new RecordUpdateUData();
                var ids   = new HashSet <string>();
                if (record.Attachments != null)
                {
                    foreach (var atta in record.Attachments)
                    {
                        ids.Add(atta.Id);
                        if (atta.Thumbnails != null)
                        {
                            foreach (var thumb in atta.Thumbnails)
                            {
                                ids.Add(thumb.Id);
                            }
                        }
                    }
                }
                udata.fileIds      = ids.ToArray();
                updateRecord.udata = udata;
            }

            var command = new RecordUpdateCommand();

            if (existingRecord != null)
            {
                command.updateRecords = new RecordUpdateRecord[] { updateRecord };
            }
            else
            {
                command.addRecords = new RecordUpdateRecord[] { updateRecord };
            }

            var rs = await Auth.ExecuteAuthCommand <RecordUpdateCommand, RecordUpdateResponse>(command);

            await this.SyncDown();
        }
Beispiel #6
0
        public async Task Login(IUserConfiguration user = null)
        {
            var configuration = Api.Storage.Get();

            user = await ResolveUserConfiguration(user, configuration);

            var username = user?.Username;
            var password = user?.Password;

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                return;
            }
            var token     = user.TwoFactorToken;
            var tokenType = "device_token";

            string           authHash = null;
            PreLoginResponse preLogin = null;

            while (true)
            {
                if (preLogin == null)
                {
                    preLogin = await Api.GetPreLogin(username);

                    authHash = null;
                }

                var    authParams = preLogin.Salt[0];
                int    iterations = authParams.Iterations;
                byte[] salt       = authParams.Salt_.ToByteArray();
                if (authHash == null)
                {
                    authHash = CryptoUtils.DeriveV1KeyHash(password, salt, iterations).Base64UrlEncode();
                }

                var command = new LoginCommand();
                command.username                 = username;
                command.authResponse             = authHash;
                command.include                  = new[] { "keys", "settings", "enforcements", "is_enterprise_admin" };
                command.twoFactorToken           = token;
                command.twoFactorType            = !string.IsNullOrEmpty(token) ? tokenType : null;
                command.deviceTokenExpiresInDays = !string.IsNullOrEmpty(token) && tokenType != "device_token" ? 9999 : (int?)null;

                var loginRs = await Api.ExecuteV2Command <LoginCommand, LoginResponse>(command);

                if (!loginRs.IsSuccess && loginRs.resultCode == "auth_failed") // invalid password
                {
                    throw new Exception("Invalid user name or password");
                }
                else
                {
                    if (!string.IsNullOrEmpty(loginRs.deviceToken))
                    {
                        token     = loginRs.deviceToken;
                        tokenType = "device_token";
                    }

                    SessionToken    = loginRs.sessionToken;
                    Username        = username;
                    accountSettings = loginRs.accountSettings;

                    if (loginRs.keys != null)
                    {
                        if (loginRs.keys.encryptedDataKey != null)
                        {
                            var key = CryptoUtils.DeriveKeyV2("data_key", password, salt, iterations);
                            DataKey = CryptoUtils.DecryptAesV2(loginRs.keys.encryptedDataKey.Base64UrlDecode(), key);
                        }
                        else
                        if (loginRs.keys.encryptionParams != null)
                        {
                            DataKey = CryptoUtils.DecryptEncryptionParams(password, loginRs.keys.encryptionParams.Base64UrlDecode());
                        }
                        else
                        {
                            throw new Exception("Missing data key");
                        }
                        if (loginRs.keys.encryptedPrivateKey != null)
                        {
                            privateKeyData = CryptoUtils.DecryptAesV1(loginRs.keys.encryptedPrivateKey.Base64UrlDecode(), DataKey);
                            privateKey     = null;
                        }
                    }
                    if (loginRs.IsSuccess)
                    {
                        EncryptedPassword = CryptoUtils.EncryptAesV2(Encoding.UTF8.GetBytes(password), DataKey);
                        TwoFactorToken    = token;
                        authResponse      = authHash;
                        IsEnterpriseAdmin = loginRs.isEnterpriseAdmin ?? false;
                        enforcements      = loginRs.enforcements;
                        StoreConfigurationIfChanged(configuration);
                        break;
                    }
                    switch (loginRs.resultCode)
                    {
                    case "need_totp":
                    case "invalid_device_token":
                    case "invalid_totp":
                        token = await Ui.GetTwoFactorCode();

                        if (!string.IsNullOrEmpty(token))
                        {
                            tokenType = "one_time";
                            continue;
                        }
                        break;

                    case "auth_expired":
                        await Ui.DisplayDialog(DialogType.Information, loginRs.message);

                        password = await this.ChangeMasterPassword(iterations);

                        if (!string.IsNullOrEmpty(password))
                        {
                            preLogin = null;
                            continue;
                        }
                        break;

                    case "auth_expired_transfer":
                        var shareAccountTo = loginRs.accountSettings.shareAccountTo;
                        if (await Ui.DisplayDialog(DialogType.Confirmation, "Do you accept Account Transfer policy?"))
                        {
                            await this.ShareAccount();

                            continue;
                        }
                        break;
                    }
                    throw new KeeperApiException(loginRs.resultCode, loginRs.message);
                }
            }
        }