1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-04 14:13:28 +01:00
bitwarden-server/util/Migrator/DbScripts/2020-09-09_00-ScriptMigrateU2FToWebAuthn.cs
2021-03-22 23:21:43 +01:00

122 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Bit.Core.Enums;
using Bit.Core.Models;
using DbUp.Engine;
using Newtonsoft.Json;
namespace Bit.Migrator.DbScripts
{
class ScriptMigrateU2FToWebAuthn : IScript
{
public string ProvideScript(Func<IDbCommand> commandFactory)
{
var cmd = commandFactory();
cmd.CommandText = "SELECT Id, TwoFactorProviders FROM [dbo].[User] WHERE TwoFactorProviders IS NOT NULL";
var users = new List<object>();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetGuid(0);
var twoFactorProviders = reader.GetString(1);
if (string.IsNullOrWhiteSpace(twoFactorProviders))
{
continue;
}
var providers = JsonConvert.DeserializeObject<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(twoFactorProviders);
if (!providers.ContainsKey(TwoFactorProviderType.U2f))
{
continue;
}
var u2fProvider = providers[TwoFactorProviderType.U2f];
if (!u2fProvider.Enabled || !HasProperMetaData(u2fProvider))
{
continue;
}
var u2fKeys = LoadKeys(u2fProvider);
var webAuthnKeys = u2fKeys.Select(key => (key.Item1, key.Item2.ToWebAuthnData()));
var webAuthnProvider = new TwoFactorProvider
{
Enabled = true,
MetaData = webAuthnKeys.ToDictionary(x => x.Item1, x => (object)x.Item2)
};
providers[TwoFactorProviderType.WebAuthn] = webAuthnProvider;
users.Add(new User
{
Id = id,
TwoFactorProviders = JsonConvert.SerializeObject(providers),
});
}
}
foreach (User user in users)
{
var command = commandFactory();
command.CommandText = "UPDATE [dbo].[User] SET TwoFactorProviders = @twoFactorProviders WHERE Id = @id";
var idParameter = command.CreateParameter();
idParameter.ParameterName = "@id";
idParameter.Value = user.Id;
var twoFactorParameter = command.CreateParameter();
twoFactorParameter.ParameterName = "@twoFactorProviders";
twoFactorParameter.Value = user.TwoFactorProviders;
command.Parameters.Add(idParameter);
command.Parameters.Add(twoFactorParameter);
command.ExecuteNonQuery();
}
return "";
}
private bool HasProperMetaData(TwoFactorProvider provider)
{
return (provider?.MetaData?.Count ?? 0) > 0;
}
private List<Tuple<string, TwoFactorProvider.U2fMetaData>> LoadKeys(TwoFactorProvider provider)
{
var keys = new List<Tuple<string, TwoFactorProvider.U2fMetaData>>();
// Support up to 5 keys
for (var i = 1; i <= 5; i++)
{
var keyName = $"Key{i}";
if (provider.MetaData.ContainsKey(keyName))
{
var key = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData[keyName]);
if (!key?.Compromised ?? false)
{
keys.Add(new Tuple<string, TwoFactorProvider.U2fMetaData>(keyName, key));
}
}
}
return keys;
}
private class User
{
public Guid Id { get; set; }
public string TwoFactorProviders { get; set; }
}
}
}