Merge pull request #155 from lanedirt/108-add-identity-generator-scaffolding-utility-project

Add identity generator utility project for EN and NL identities
This commit is contained in:
Leendert de Borst
2024-08-05 11:35:56 -07:00
committed by GitHub
32 changed files with 1723 additions and 398 deletions

View File

@@ -27,4 +27,15 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Identity\Implementations\Dictionaries\en\firstnames_female" />
<EmbeddedResource Include="Identity\Implementations\Dictionaries\en\firstnames_male" />
<EmbeddedResource Include="Identity\Implementations\Dictionaries\en\lastnames" />
<EmbeddedResource Include="Identity\Implementations\Dictionaries\nl\firstnames_female" />
<None Remove="Identity\Implementations\Lists\nl\firstnames" />
<EmbeddedResource Include="Identity\Implementations\Dictionaries\nl\firstnames_male" />
<None Remove="Identity\Implementations\Lists\nl\lastnames" />
<EmbeddedResource Include="Identity\Implementations\Dictionaries\nl\lastnames" />
</ItemGroup>
</Project>

View File

@@ -4,6 +4,7 @@
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity;
/// <summary>

View File

@@ -0,0 +1,137 @@
//-----------------------------------------------------------------------
// <copyright file="IdentityGenerator.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Implementations.Base;
using System.Reflection;
using AliasGenerators.Identity;
using AliasGenerators.Identity.Models;
/// <summary>
/// Dutch identity generator which implements IIdentityGenerator and generates
/// random dutch identities.
/// </summary>
public abstract class IdentityGenerator : IIdentityGenerator
{
/// <summary>
/// List of male first names in memory.
/// </summary>
private readonly List<string> _firstNamesMale;
/// <summary>
/// List of female first names in memory.
/// </summary>
private readonly List<string> _firstNamesFemale;
/// <summary>
/// List of last names in memory.
/// </summary>
private readonly List<string> _lastNames;
/// <summary>
/// Random instance.
/// </summary>
private readonly Random _random = new();
/// <summary>
/// Initializes a new instance of the <see cref="IdentityGenerator"/> class.
/// </summary>
protected IdentityGenerator()
{
_firstNamesMale = LoadList(FirstNamesListMale);
_firstNamesFemale = LoadList(FirstNamesListFemale);
_lastNames = LoadList(LastNamesList);
}
/// <summary>
/// Gets namespace path to the male first names list for the correct language.
/// </summary>
protected virtual string FirstNamesListMale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_male";
/// <summary>
/// Gets namespace path to the female first names list for the correct language.
/// </summary>
protected virtual string FirstNamesListFemale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_female";
/// <summary>
/// Gets namespace path to the last names list for the correct language.
/// </summary>
protected virtual string LastNamesList => "AliasGenerators.Identity.Implementations.Dictionaries.nl.lastnames";
/// <inheritdoc/>
public async Task<Identity> GenerateRandomIdentityAsync()
{
await Task.Yield(); // Add an await statement to make the method truly asynchronous.
// Generate identity.
var identity = new Identity();
// Determine gender.
if (_random.Next(2) == 0)
{
identity.FirstName = _firstNamesMale[_random.Next(_firstNamesMale.Count)];
identity.Gender = Gender.Male;
}
else
{
identity.FirstName = _firstNamesFemale[_random.Next(_firstNamesFemale.Count)];
identity.Gender = Gender.Female;
}
identity.LastName = _lastNames[_random.Next(_lastNames.Count)];
// Generate random date of birth between 21 and 65 years of age.
identity.BirthDate = GenerateRandomDateOfBirth();
identity.EmailPrefix = new UsernameEmailGenerator().GenerateEmailPrefix(identity);
identity.NickName = new UsernameEmailGenerator().GenerateUsername(identity);
return identity;
}
/// <summary>
/// Load a list of words from a resource file.
/// </summary>
/// <param name="resourceName">Name of the resource file to load.</param>
/// <returns>List of words from the resource file.</returns>
/// <exception cref="FileNotFoundException">Thrown if resource file cannot be found.</exception>
private static List<string> LoadList(string resourceName)
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream == null)
{
throw new FileNotFoundException("Resource '" + resourceName + "' not found.", resourceName);
}
using var reader = new StreamReader(stream);
var words = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line != null)
{
words.Add(line);
}
}
return words;
}
/// <summary>
/// Generate a random date of birth.
/// </summary>
/// <returns>DateTime representing date of birth.</returns>
private DateTime GenerateRandomDateOfBirth()
{
// Generate random date of birth between 21 and 65 years of age.
var now = DateTime.Now;
var minDob = now.AddYears(-65);
var maxDob = now.AddYears(-21);
return minDob.AddDays(_random.Next((int)(maxDob - minDob).TotalDays));
}
}

View File

@@ -0,0 +1,153 @@
Emily
Emma
Olivia
Ava
Sophia
Isabella
Mia
Charlotte
Amelia
Harper
Evelyn
Abigail
Elizabeth
Sofia
Avery
Ella
Madison
Scarlett
Victoria
Aria
Grace
Chloe
Camila
Penelope
Riley
Layla
Zoey
Nora
Lily
Eleanor
Hannah
Lillian
Addison
Aubrey
Ellie
Stella
Natalie
Zoe
Leah
Hazel
Violet
Aurora
Savannah
Audrey
Brooklyn
Bella
Claire
Skylar
Lucy
Paisley
Everly
Anna
Caroline
Nova
Genesis
Emilia
Kennedy
Samantha
Maya
Willow
Kinsley
Naomi
Aaliyah
Elena
Sarah
Ariana
Allison
Gabriella
Alice
Madelyn
Cora
Ruby
Eva
Serenity
Autumn
Adeline
Hailey
Gianna
Valentina
Isla
Eliana
Quinn
Nevaeh
Ivy
Sadie
Piper
Lydia
Alexa
Josephine
Emery
Julia
Delilah
Arianna
Vivian
Kaylee
Sophie
Brielle
Madeline
Peyton
Rylee
Clara
Hadley
Melanie
Mackenzie
Reagan
Adalyn
Liliana
Aubree
Jade
Katherine
Isabelle
Natalia
Raelynn
Maria
Athena
Ximena
Arya
Leilani
Taylor
Faith
Rose
Kylie
Alexandra
Mary
Margaret
Lyla
Ashley
Amaya
Eliza
Brianna
Bailey
Andrea
Khloe
Jasmine
Melody
Iris
Isabel
Norah
Annabelle
Valeria
Emerson
Adalynn
Ryleigh
Eden
Emersyn
Anastasia
Kayla
Alyssa
Anna
Juliana
Charlie
Lucia
Stella

View File

@@ -0,0 +1,142 @@
Michael
Christopher
Matthew
Joshua
Daniel
David
Andrew
Joseph
James
John
Robert
William
Ryan
Jason
Nicholas
Jonathan
Jacob
Brandon
Tyler
Zachary
Kevin
Justin
Benjamin
Anthony
Samuel
Thomas
Alexander
Ethan
Noah
Dylan
Nathan
Christian
Austin
Adam
Caleb
Cody
Jordan
Logan
Aaron
Kyle
Jose
Brian
Gabriel
Timothy
Luke
Jared
Connor
Sean
Evan
Isaac
Jack
Cameron
Hunter
Jackson
Charles
Devin
Stephen
Patrick
Steven
Elijah
Scott
Mark
Jeffrey
Corey
Juan
Luis
Derek
Chase
Travis
Alex
Spencer
Ian
Trevor
Bryan
Tanner
Marcus
Jeremy
Eric
Jaden
Garrett
Isaiah
Dustin
Jesse
Seth
Blake
Nathaniel
Mason
Liam
Paul
Carlos
Mitchell
Parker
Lucas
Richard
Cole
Adrian
Colin
Bradley
Jesus
Peter
Kenneth
Joel
Victor
Bryce
Casey
Vincent
Edward
Henry
Dominic
Riley
Shane
Dalton
Grant
Shawn
Braden
Caden
Max
Hayden
Owen
Brett
Trevor
Philip
Brendan
Wesley
Aidan
Brady
Colton
Tristan
George
Gavin
Dawson
Miguel
Antonio
Nolan
Dakota
Jace
Collin
Preston
Levi
Alan
Jorge
Carson

View File

@@ -0,0 +1,167 @@
Smith
Johnson
Williams
Brown
Jones
Garcia
Miller
Davis
Rodriguez
Martinez
Hernandez
Lopez
Gonzalez
Wilson
Anderson
Thomas
Taylor
Moore
Jackson
Martin
Lee
Perez
Thompson
White
Harris
Sanchez
Clark
Ramirez
Lewis
Robinson
Walker
Young
Allen
King
Wright
Scott
Torres
Nguyen
Hill
Flores
Green
Adams
Nelson
Baker
Hall
Rivera
Campbell
Mitchell
Carter
Roberts
Gomez
Phillips
Evans
Turner
Diaz
Parker
Cruz
Edwards
Collins
Reyes
Stewart
Morris
Morales
Murphy
Cook
Rogers
Gutierrez
Ortiz
Morgan
Cooper
Peterson
Bailey
Reed
Kelly
Howard
Ramos
Kim
Cox
Ward
Richardson
Watson
Brooks
Chavez
Wood
James
Bennett
Gray
Mendoza
Ruiz
Hughes
Price
Alvarez
Castillo
Sanders
Patel
Myers
Long
Ross
Foster
Jimenez
Powell
Jenkins
Perry
Russell
Sullivan
Bell
Coleman
Butler
Henderson
Barnes
Gonzales
Fisher
Vasquez
Simmons
Romero
Jordan
Patterson
Alexander
Hamilton
Graham
Reynolds
Griffin
Wallace
Moreno
West
Cole
Hayes
Bryant
Herrera
Gibson
Ellis
Tran
Medina
Aguilar
Stevens
Murray
Ford
Castro
Marshall
Owens
Harrison
Fernandez
McDonald
Woods
Washington
Kennedy
Wells
Vargas
Henry
Chen
Freeman
Webb
Tucker
Guzman
Burns
Crawford
Olson
Simpson
Porter
Hunter
Gordon
Mendez
Silva
Shaw
Snyder
Mason
Dixon

View File

@@ -0,0 +1,104 @@
Emma
Sophie
Julia
Mila
Tess
Sara
Anna
Noor
Lotte
Liv
Eva
Nora
Zoë
Evi
Yara
Saar
Nina
Fenna
Lieke
Fleur
Isa
Roos
Lynn
Sofie
Sarah
Milou
Olivia
Maud
Lisa
Vera
Luna
Lina
Noa
Feline
Loïs
Lena
Floor
Charlotte
Esmee
Julie
Iris
Lara
Amber
Hailey
Mia
Lize
Isabelle
Cato
Fenne
Sanne
Norah
Sophia
Ella
Nova
Elin
Femke
Lizzy
Linde
Lauren
Rosalie
Lana
Emily
Elise
Esmée
Anne
Isabelle
Demi
Hannah
Liva
Suze
Fay
Isabel
Benthe
Evi
Amy
Jasmijn
Niene
Sterre
Fenna
Fiene
Liz
Ise
Mara
Nienke
Indy
Romy
Lola
Puck
Nora
Merel
Bente
Eline
Lily
Leah
Naomi
Mirthe
Valerie
Noor
Liva
Jade
Juul
Lise
Myrthe
Veerle

View File

@@ -0,0 +1,101 @@
Daan
Luuk
Sem
Finn
Milan
Levi
Noah
Lucas
Jesse
Thijs
Jayden
Bram
Lars
Ruben
Thomas
Tim
Sam
Liam
Julian
Mees
Ties
Sven
Max
Gijs
David
Stijn
Jasper
Niels
Jens
Timo
Cas
Joep
Roan
Tom
Tygo
Teun
Siem
Mats
Thijmen
Rens
Niek
Tobias
Dex
Hugo
Robin
Nick
Floris
Pepijn
Boaz
Olivier
Luca
Jurre
Jelle
Guus
Koen
Bart
Olaf
Wessel
Daniël
Job
Sander
Tijmen
Kai
Quinten
Owen
Morris
Fedde
Joris
Jesper
Mick
Ryan
Milo
Stan
Benjamin
Melle
Jip
Dylan
Brent
Mick
Dean
Otis
Abel
Luc
Sepp
Vince
Rayan
Noud
Hidde
Fabian
Jort
Damian
Boris
Sil
Moos
Aiden
Sep
Mika
Mijs
Mika
Felix
Merlijn

View File

@@ -0,0 +1,106 @@
de Jong
Jansen
de Vries
van den Berg
van Dijk
Bakker
Janssen
Visser
Smit
Meijer
de Boer
Mulder
de Groot
Bos
Vos
Peters
Hendriks
van Leeuwen
Dekker
Brouwer
de Wit
Dijkstra
Smits
de Graaf
van der Meer
van der Linden
Kok
Jacobs
de Haan
Vermeulen
van den Heuvel
van der Veen
van den Broek
de Bruijn
de Bruin
van der Heijden
Schouten
van Beek
Willems
van Vliet
van de Ven
Hoekstra
Maas
Verhoeven
Koster
van Dam
van der Wal
Prins
Blom
Huisman
Peeters
Kuipers
van Veen
van Dongen
Veenstra
Kramer
van den Bosch
van der Meulen
Mol
Zwart
van der Laan
Martens
van de Pol
Postma
Tromp
Borst
Boon
van Doorn
Jonker
van der Velden
Willemsen
van Wijk
Groen
Gerritsen
Bosch
van Loon
van der Ploeg
de Ruiter
Molenaar
Boer
Klein
de Koning
van de Kamp
van der Horst
Verbeek
Vink
Goossens
Scholten
Hartman
van Dalen
van Elst
Brink
Boekel
van de Berg
Berends
van der Hoek
Kuiper
Kooijman
de Lange
van der Sluis
van Gelder
Martens
van Asselt
Timmermans
van Vliet
van Rijn

View File

@@ -0,0 +1,32 @@
//-----------------------------------------------------------------------
// <copyright file="IdentityGeneratorFactory.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Implementations;
using AliasGenerators.Identity.Implementations.Base;
/// <summary>
/// Identity generator factory which creates an identity generator based on the language code.
/// </summary>
public static class IdentityGeneratorFactory
{
/// <summary>
/// Creates an identity generator based on the language code.
/// </summary>
/// <param name="languageCode">Two letter language code.</param>
/// <returns>The IdentityGenerator for the requested language.</returns>
/// <exception cref="ArgumentException">Thrown if no identity generator is found for the requested language.</exception>
public static IdentityGenerator CreateIdentityGenerator(string languageCode)
{
return languageCode.ToLower() switch
{
"nl" => new IdentityGeneratorNl(),
"en" => new IdentityGeneratorEn(),
_ => throw new ArgumentException($"Unsupported language code: {languageCode}", nameof(languageCode)),
};
}
}

View File

@@ -1,39 +0,0 @@
//-----------------------------------------------------------------------
// <copyright file="FigIdentityGenerator.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Implementations;
using System.Text.Json;
/// <summary>
/// Identity generator which generates random identities using the identiteitgenerator.nl semi-public API.
/// </summary>
public class FigIdentityGenerator : IIdentityGenerator
{
private static readonly HttpClient HttpClient = new();
private static readonly string Url = "https://api.identiteitgenerator.nl/generate/identity";
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
};
/// <inheritdoc/>
public async Task<Identity.Models.Identity> GenerateRandomIdentityAsync()
{
var response = await HttpClient.GetAsync(Url);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var identity = JsonSerializer.Deserialize<Identity.Models.Identity>(json, JsonSerializerOptions);
if (identity is null)
{
throw new InvalidOperationException("Failed to deserialize the identity from FIG WebApi.");
}
return identity;
}
}

View File

@@ -0,0 +1,26 @@
//-----------------------------------------------------------------------
// <copyright file="IdentityGeneratorEn.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Implementations;
using AliasGenerators.Identity.Implementations.Base;
/// <summary>
/// Dutch identity generator which implements IIdentityGenerator and generates
/// random dutch identities.
/// </summary>
public class IdentityGeneratorEn : IdentityGenerator
{
/// <inheritdoc cref="IdentityGenerator.FirstNamesListMale" />
protected override string FirstNamesListMale => "AliasGenerators.Identity.Implementations.Dictionaries.en.firstnames_male";
/// <inheritdoc cref="IdentityGenerator.FirstNamesListFemale" />
protected override string FirstNamesListFemale => "AliasGenerators.Identity.Implementations.Dictionaries.en.firstnames_female";
/// <inheritdoc cref="IdentityGenerator.LastNamesList" />
protected override string LastNamesList => "AliasGenerators.Identity.Implementations.Dictionaries.en.lastnames";
}

View File

@@ -0,0 +1,26 @@
//-----------------------------------------------------------------------
// <copyright file="IdentityGeneratorNl.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Implementations;
using AliasGenerators.Identity.Implementations.Base;
/// <summary>
/// Dutch identity generator which implements IIdentityGenerator and generates
/// random dutch identities.
/// </summary>
public class IdentityGeneratorNl : IdentityGenerator
{
/// <inheritdoc cref="IdentityGenerator.FirstNamesListMale" />
protected override string FirstNamesListMale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_male";
/// <inheritdoc cref="IdentityGenerator.FirstNamesListFemale" />
protected override string FirstNamesListFemale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_female";
/// <inheritdoc cref="IdentityGenerator.LastNamesList" />
protected override string LastNamesList => "AliasGenerators.Identity.Implementations.Dictionaries.nl.lastnames";
}

View File

@@ -1,27 +0,0 @@
//-----------------------------------------------------------------------
// <copyright file="StaticIdentityGenerator.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Implementations;
using AliasGenerators.Identity;
/// <summary>
/// Static identity generator which implements IIdentityGenerator but always returns
/// the same static identity for testing purposes.
/// </summary>
public class StaticIdentityGenerator : IIdentityGenerator
{
/// <inheritdoc/>
public async Task<Identity.Models.Identity> GenerateRandomIdentityAsync()
{
await Task.Yield(); // Add an await statement to make the method truly asynchronous.
return new Identity.Models.Identity
{
FirstName = "John",
LastName = "Doe",
};
}
}

View File

@@ -1,38 +0,0 @@
//-----------------------------------------------------------------------
// <copyright file="Address.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Models;
/// <summary>
/// Address model.
/// </summary>
public class Address
{
/// <summary>
/// Gets or sets the street.
/// </summary>
public string Street { get; set; } = null!;
/// <summary>
/// Gets or sets the city.
/// </summary>
public string City { get; set; } = null!;
/// <summary>
/// Gets or sets the state.
/// </summary>
public string State { get; set; } = null!;
/// <summary>
/// Gets or sets the zip code.
/// </summary>
public string ZipCode { get; set; } = null!;
/// <summary>
/// Gets or sets the country.
/// </summary>
public string Country { get; set; } = null!;
}

View File

@@ -0,0 +1,24 @@
//-----------------------------------------------------------------------
// <copyright file="Gender.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Models;
/// <summary>
/// Identity model.
/// </summary>
public enum Gender
{
/// <summary>
/// Male gender.
/// </summary>
Male,
/// <summary>
/// Female gender.
/// </summary>
Female,
}

View File

@@ -4,6 +4,7 @@
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Models;
/// <summary>
@@ -19,7 +20,7 @@ public class Identity
/// <summary>
/// Gets or sets the gender.
/// </summary>
public int Gender { get; set; }
public Gender Gender { get; set; }
/// <summary>
/// Gets or sets the first name.
@@ -41,48 +42,8 @@ public class Identity
/// </summary>
public DateTime BirthDate { get; set; }
/// <summary>
/// Gets or sets the address.
/// </summary>
public Address Address { get; set; } = null!;
/// <summary>
/// Gets or sets the job.
/// </summary>
public Job Job { get; set; } = null!;
/// <summary>
/// Gets or sets the hobbies.
/// </summary>
public List<string> Hobbies { get; set; } = null!;
/// <summary>
/// Gets or sets the email address prefix.
/// </summary>
public string EmailPrefix { get; set; } = null!;
/// <summary>
/// Gets or sets the password.
/// </summary>
public string Password { get; set; } = null!;
/// <summary>
/// Gets or sets the phone mobile.
/// </summary>
public string PhoneMobile { get; set; } = null!;
/// <summary>
/// Gets or sets the bank account IBAN.
/// </summary>
public string BankAccountIBAN { get; set; } = null!;
/// <summary>
/// Gets or sets the profile photo in base64 format.
/// </summary>
public string ProfilePhotoBase64 { get; set; } = null!;
/// <summary>
/// Gets or sets the profile photo prompt.
/// </summary>
public string ProfilePhotoPrompt { get; set; } = null!;
}

View File

@@ -1,38 +0,0 @@
//-----------------------------------------------------------------------
// <copyright file="Job.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity.Models;
/// <summary>
/// Job model.
/// </summary>
public class Job
{
/// <summary>
/// Gets or sets the title.
/// </summary>
public string Title { get; set; } = null!;
/// <summary>
/// Gets or sets the company.
/// </summary>
public string Company { get; set; } = null!;
/// <summary>
/// Gets or sets the salary.
/// </summary>
public string Salary { get; set; } = null!;
/// <summary>
/// Gets or sets the calculated salary.
/// </summary>
public decimal SalaryCalculated { get; set; }
/// <summary>
/// Gets or sets the description.
/// </summary>
public string Description { get; set; } = null!;
}

View File

@@ -0,0 +1,143 @@
//-----------------------------------------------------------------------
// <copyright file="UsernameEmailGenerator.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasGenerators.Identity;
using System.Text.RegularExpressions;
/// <summary>
/// Generates usernames and email prefixes based on an identity.
/// </summary>
public class UsernameEmailGenerator
{
/// <summary>
/// Minimum length of the generated username.
/// </summary>
private const int MinLength = 6;
/// <summary>
/// Maximum length of the generated username.
/// </summary>
private const int MaxLength = 20;
/// <summary>
/// Create a new random instance for generating random values.
/// </summary>
private readonly Random _random = new();
/// <summary>
/// List of allowed symbols to use in usernames.
/// </summary>
private readonly List<string> _symbols = [".", "-"];
/// <summary>
/// Generates a username based on a identity.
/// </summary>
/// <param name="identity">Identity to generate username for.</param>
/// <returns>Username as string.</returns>
public string GenerateUsername(Models.Identity identity)
{
// Generate username based on email prefix but strip all non-alphanumeric characters
string username = GenerateEmailPrefix(identity);
username = Regex.Replace(username, @"[^a-zA-Z0-9]", string.Empty, RegexOptions.NonBacktracking);
// Adjust length
if (username.Length < MinLength)
{
username += GenerateRandomString(MinLength - username.Length);
}
else if (username.Length > MaxLength)
{
username = username.Substring(0, MaxLength);
}
return username;
}
/// <summary>
/// Generates a valid email prefix based on an identity.
/// </summary>
/// <param name="identity">Identity to generate email prefix for.</param>
/// <returns>Valid email prefix as string.</returns>
public string GenerateEmailPrefix(Models.Identity identity)
{
var parts = new List<string>();
// Use first initial + last name
if (_random.Next(2) == 0)
{
parts.Add(identity.FirstName.Substring(0, 1).ToLower() + identity.LastName.ToLower());
}
else
{
// Use full name
parts.Add((identity.FirstName + identity.LastName).ToLower());
}
// Add birth year
if (_random.Next(2) == 0)
{
parts.Add(identity.BirthDate.Year.ToString().Substring(2));
}
// Join parts and sanitize
var emailPrefix = string.Join(GetRandomSymbol(), parts);
emailPrefix = SanitizeEmailPrefix(emailPrefix);
// Adjust length
if (emailPrefix.Length < MinLength)
{
emailPrefix += GenerateRandomString(MinLength - emailPrefix.Length);
}
else if (emailPrefix.Length > MaxLength)
{
emailPrefix = emailPrefix.Substring(0, MaxLength);
}
return emailPrefix;
}
/// <summary>
/// Sanitize the email prefix by removing invalid characters and ensuring it's a valid email prefix.
/// </summary>
/// <param name="input">The input string to sanitize.</param>
/// <returns>The sanitized string.</returns>
private static string SanitizeEmailPrefix(string input)
{
// Remove any character that's not a letter, number, dot, underscore, or hyphen including special characters
string sanitized = Regex.Replace(input, @"[^a-zA-Z0-9._-]", string.Empty, RegexOptions.NonBacktracking);
// Remove consecutive dots, underscores, or hyphens
sanitized = Regex.Replace(sanitized, @"[-_.]{2,}", m => m.Value[0].ToString(), RegexOptions.NonBacktracking);
// Ensure it doesn't start or end with a dot, underscore, or hyphen
sanitized = sanitized.Trim('.', '_', '-');
return sanitized;
}
/// <summary>
/// Get a random symbol from the list of symbols.
/// </summary>
/// <returns>Random symbol.</returns>
private string GetRandomSymbol()
{
return _random.Next(3) == 0 ? _symbols[_random.Next(_symbols.Count)] : string.Empty;
}
/// <summary>
/// Generate a random string of a given length.
/// </summary>
/// <param name="length">Length of string to generate.</param>
/// <returns>String with random characters.</returns>
private string GenerateRandomString(int length)
{
const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[_random.Next(s.Length)]).ToArray());
}
}

View File

@@ -21,7 +21,7 @@ using Microsoft.AspNetCore.Mvc;
public class IdentityController(UserManager<AliasVaultUser> userManager) : AuthenticatedRequestController(userManager)
{
/// <summary>
/// Proxies the request to the identity generator to generate a random identity.
/// Proxies the request to the english identity generator to generate a random identity.
/// </summary>
/// <returns>Identity model.</returns>
[HttpGet("Generate")]
@@ -33,7 +33,7 @@ public class IdentityController(UserManager<AliasVaultUser> userManager) : Authe
return Unauthorized();
}
var identityGenerator = new FigIdentityGenerator();
var identityGenerator = new IdentityGeneratorEn();
return Ok(await identityGenerator.GenerateRandomIdentityAsync());
}
}

View File

@@ -3,6 +3,8 @@
@inherits MainBase
@inject CredentialService CredentialService
@using System.Globalization
@using AliasGenerators.Identity.Implementations
@using AliasGenerators.Identity.Models
@using AliasGenerators.Password
@using AliasGenerators.Password.Implementations
@@ -126,30 +128,6 @@ else
<EditFormRow Id="birthdate" Label="Birth Date" @bind-Value="Obj.AliasBirthDate"></EditFormRow>
<ValidationMessage For="() => Obj.AliasBirthDate"/>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="street" Label="Address Street" @bind-Value="Obj.Alias.AddressStreet"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="city" Label="Address City" @bind-Value="Obj.Alias.AddressCity"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="state" Label="Address State" @bind-Value="Obj.Alias.AddressState"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="zipcode" Label="Address Zip Code" @bind-Value="Obj.Alias.AddressZipCode"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="country" Label="Address Country" @bind-Value="Obj.Alias.AddressCountry"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="hobbies" Label="Hobbies" @bind-Value="Obj.Alias.Hobbies"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="phone-mobile" Label="Phone Mobile" @bind-Value="Obj.Alias.PhoneMobile"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditFormRow Id="iban" Label="Bank Account IBAN" @bind-Value="Obj.Alias.BankAccountIBAN"></EditFormRow>
</div>
</div>
</div>
@@ -266,27 +244,19 @@ else
StateHasChanged();
// Generate a random identity using the IIdentityGenerator implementation.
var identity = await CredentialService.GenerateRandomIdentityAsync();
var identity = await IdentityGeneratorFactory.CreateIdentityGenerator(DbService.Settings.DefaultIdentityLanguage).GenerateRandomIdentityAsync();
// Generate random values for the Identity properties
Obj.Username = identity.NickName;
Obj.Alias.FirstName = identity.FirstName;
Obj.Alias.LastName = identity.LastName;
Obj.Alias.NickName = identity.NickName;
Obj.Alias.Gender = identity.Gender == 1 ? "Male" : "Female";
Obj.Alias.Gender = identity.Gender == Gender.Male ? "Male" : "Female";
Obj.AliasBirthDate = identity.BirthDate.ToString("yyyy-MM-dd");
Obj.Alias.AddressStreet = identity.Address.Street;
Obj.Alias.AddressCity = identity.Address.City;
Obj.Alias.AddressState = identity.Address.State;
Obj.Alias.AddressZipCode = identity.Address.ZipCode;
Obj.Alias.AddressCountry = identity.Address.Country;
Obj.Alias.Hobbies = identity.Hobbies[0];
// Set the email
var emailDomain = GetDefaultEmailDomain();
Obj.Alias.Email = $"{identity.EmailPrefix}@{emailDomain}";
Obj.Alias.PhoneMobile = identity.PhoneMobile;
Obj.Alias.BankAccountIBAN = identity.BankAccountIBAN;
// Generate password
GenerateRandomPassword();

View File

@@ -95,40 +95,6 @@ else
</div>
</form>
</div>
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-4 text-xl font-semibold dark:text-white">Contact</h3>
<form action="#">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Phone" Value="@(Alias.Alias.PhoneMobile)"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="IBAN" Value="@(Alias.Alias.BankAccountIBAN)"></CopyPasteFormRow>
</div>
</div>
</form>
</div>
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-4 text-xl font-semibold dark:text-white">Address</h3>
<form action="#">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Street" Value="@(Alias.Alias.AddressStreet)"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Postal code" Value="@(Alias.Alias.AddressZipCode)"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="City" Value="@(Alias.Alias.AddressCity)"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Country" Value="@(Alias.Alias.AddressCountry)"></CopyPasteFormRow>
</div>
</div>
</form>
</div>
</div>
</div>
}

View File

@@ -44,6 +44,21 @@
</div>
</div>
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-4 text-lg font-medium text-gray-900 dark:text-white">Identity Settings</h3>
<div class="mb-4">
<label for="defaultEmailDomain" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Identity generation language</label>
<select @bind="DefaultIdentityLanguage" @bind:after="UpdateDefaultIdentityLanguage" id="defaultIdentityLanguage" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option value="en">English</option>
<option value="nl">Dutch</option>
</select>
<span class="block text-sm font-normal text-gray-500 truncate dark:text-gray-400">
Set the default language that will be used when generating new identities.
</span>
</div>
</div>
@code {
private List<string> PrivateDomains => Config.PrivateEmailDomains;
private List<string> PublicDomains => Config.PublicEmailDomains;
@@ -51,6 +66,7 @@
private string DefaultEmailDomain { get; set; } = string.Empty;
private bool AutoEmailRefresh { get; set; }
private string DefaultIdentityLanguage { get; set; } = string.Empty;
/// <inheritdoc />
protected override async Task OnInitializedAsync()
@@ -60,6 +76,7 @@
DefaultEmailDomain = DbService.Settings.DefaultEmailDomain;
AutoEmailRefresh = DbService.Settings.AutoEmailRefresh;
DefaultIdentityLanguage = DbService.Settings.DefaultIdentityLanguage;
}
/// <summary>
@@ -79,4 +96,13 @@
await DbService.Settings.SetAutoEmailRefresh(AutoEmailRefresh);
StateHasChanged();
}
/// <summary>
/// Updates the auto email refresh setting.
/// </summary>
private async Task UpdateDefaultIdentityLanguage()
{
await DbService.Settings.SetDefaultIdentityLanguage(DefaultIdentityLanguage);
StateHasChanged();
}
}

View File

@@ -64,15 +64,7 @@ public class CredentialService(HttpClient httpClient, DbService dbService)
LastName = loginObject.Alias.LastName,
BirthDate = loginObject.Alias.BirthDate,
Gender = loginObject.Alias.Gender,
AddressStreet = loginObject.Alias.AddressStreet,
AddressCity = loginObject.Alias.AddressCity,
AddressState = loginObject.Alias.AddressState,
AddressZipCode = loginObject.Alias.AddressZipCode,
AddressCountry = loginObject.Alias.AddressCountry,
Hobbies = loginObject.Alias.Hobbies,
Email = loginObject.Alias.Email,
PhoneMobile = loginObject.Alias.PhoneMobile,
BankAccountIBAN = loginObject.Alias.BankAccountIBAN,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow,
},
@@ -137,15 +129,7 @@ public class CredentialService(HttpClient httpClient, DbService dbService)
login.Alias.LastName = loginObject.Alias.LastName;
login.Alias.BirthDate = loginObject.Alias.BirthDate;
login.Alias.Gender = loginObject.Alias.Gender;
login.Alias.AddressStreet = loginObject.Alias.AddressStreet;
login.Alias.AddressCity = loginObject.Alias.AddressCity;
login.Alias.AddressState = loginObject.Alias.AddressState;
login.Alias.AddressZipCode = loginObject.Alias.AddressZipCode;
login.Alias.AddressCountry = loginObject.Alias.AddressCountry;
login.Alias.Hobbies = loginObject.Alias.Hobbies;
login.Alias.Email = loginObject.Alias.Email;
login.Alias.PhoneMobile = loginObject.Alias.PhoneMobile;
login.Alias.BankAccountIBAN = loginObject.Alias.BankAccountIBAN;
login.Passwords = loginObject.Passwords;

View File

@@ -27,7 +27,7 @@ public class SettingsService
private bool _initialized;
/// <summary>
/// Gets the DefaultEmailDomain setting asynchronously.
/// Gets the DefaultEmailDomain setting.
/// </summary>
/// <returns>Default email domain as string.</returns>
public string DefaultEmailDomain => GetSetting("DefaultEmailDomain");
@@ -39,19 +39,32 @@ public class SettingsService
public bool AutoEmailRefresh => GetSetting<bool>("AutoEmailRefresh", true);
/// <summary>
/// Sets the DefaultEmailDomain setting asynchronously.
/// Gets the DefaultIdentityLanguage setting.
/// </summary>
/// <param name="value">The new DeafultEmailDomain setting.</param>
/// <returns>Default identity language as two-letter code.</returns>
public string DefaultIdentityLanguage => GetSetting<string>("DefaultIdentityLanguage", "en")!;
/// <summary>
/// Sets the DefaultEmailDomain setting.
/// </summary>
/// <param name="value">The new DefaultEmailDomain setting.</param>
/// <returns>Task.</returns>
public Task SetDefaultEmailDomain(string value) => SetSettingAsync("DefaultEmailDomain", value);
/// <summary>
/// Sets the AutoEmailRefresh setting asynchronously as a string.
/// Sets the AutoEmailRefresh setting as a string.
/// </summary>
/// <param name="value">The new value.</param>
/// <returns>Task.</returns>
public Task SetAutoEmailRefresh(bool value) => SetSettingAsync<bool>("AutoEmailRefresh", value);
/// <summary>
/// Sets the DefaultIdentityLanguage setting.
/// </summary>
/// <param name="value">The new value.</param>
/// <returns>Task.</returns>
public Task SetDefaultIdentityLanguage(string value) => SetSettingAsync("DefaultIdentityLanguage", value);
/// <summary>
/// Initializes the settings service asynchronously.
/// </summary>

View File

@@ -53,65 +53,12 @@ public class Alias
/// </summary>
public DateTime BirthDate { get; set; }
/// <summary>
/// Gets or sets the address street.
/// </summary>
[StringLength(255)]
[Column(TypeName = "VARCHAR")]
public string? AddressStreet { get; set; }
/// <summary>
/// Gets or sets the address city.
/// </summary>
[StringLength(255)]
[Column(TypeName = "VARCHAR")]
public string? AddressCity { get; set; }
/// <summary>
/// Gets or sets the address state.
/// </summary>
[StringLength(255)]
[Column(TypeName = "VARCHAR")]
public string? AddressState { get; set; }
/// <summary>
/// Gets or sets the address zip code.
/// </summary>
[StringLength(255)]
[Column(TypeName = "VARCHAR")]
public string? AddressZipCode { get; set; }
/// <summary>
/// Gets or sets the address country.
/// </summary>
[StringLength(255)]
[Column(TypeName = "VARCHAR")]
public string? AddressCountry { get; set; }
/// <summary>
/// Gets or sets the hobbies in CSV format, can contain multiple values separated by ";".
/// </summary>
[StringLength(255)]
public string? Hobbies { get; set; }
/// <summary>
/// Gets or sets the generated email.
/// </summary>
[StringLength(255)]
public string? Email { get; set; }
/// <summary>
/// Gets or sets the random generated mobile phone number.
/// </summary>
[StringLength(255)]
public string? PhoneMobile { get; set; }
/// <summary>
/// Gets or sets the generated IBAN bank account number.
/// </summary>
[StringLength(255)]
public string? BankAccountIBAN { get; set; }
/// <summary>
/// Gets or sets the created timestamp.
/// </summary>

View File

@@ -0,0 +1,296 @@
// <auto-generated />
using System;
using AliasClientDb;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AliasClientDb.Migrations
{
[DbContext(typeof(AliasClientDbContext))]
[Migration("20240805122422_1.3.0-UpdateIdentityStructure")]
partial class _130UpdateIdentityStructure
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.7")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true);
modelBuilder.Entity("AliasClientDb.Alias", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("BirthDate")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<string>("FirstName")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("Gender")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("LastName")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("NickName")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Aliases");
});
modelBuilder.Entity("AliasClientDb.Attachment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<Guid>("CredentialId")
.HasColumnType("TEXT");
b.Property<string>("Filename")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CredentialId");
b.ToTable("Attachment");
});
modelBuilder.Entity("AliasClientDb.Credential", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("AliasId")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Notes")
.HasColumnType("TEXT");
b.Property<Guid>("ServiceId")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("AliasId");
b.HasIndex("ServiceId");
b.ToTable("Credentials");
});
modelBuilder.Entity("AliasClientDb.EncryptionKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<bool>("IsPrimary")
.HasColumnType("INTEGER");
b.Property<string>("PrivateKey")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("TEXT");
b.Property<string>("PublicKey")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("EncryptionKeys");
});
modelBuilder.Entity("AliasClientDb.Password", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<Guid>("CredentialId")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CredentialId");
b.ToTable("Passwords");
});
modelBuilder.Entity("AliasClientDb.Service", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<byte[]>("Logo")
.HasColumnType("BLOB");
b.Property<string>("Name")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.Property<string>("Url")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Services");
});
modelBuilder.Entity("AliasClientDb.Setting", b =>
{
b.Property<string>("Key")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("Key");
b.ToTable("Settings");
});
modelBuilder.Entity("AliasClientDb.Attachment", b =>
{
b.HasOne("AliasClientDb.Credential", "Credential")
.WithMany("Attachments")
.HasForeignKey("CredentialId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Credential");
});
modelBuilder.Entity("AliasClientDb.Credential", b =>
{
b.HasOne("AliasClientDb.Alias", "Alias")
.WithMany("Credentials")
.HasForeignKey("AliasId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AliasClientDb.Service", "Service")
.WithMany("Credentials")
.HasForeignKey("ServiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Alias");
b.Navigation("Service");
});
modelBuilder.Entity("AliasClientDb.Password", b =>
{
b.HasOne("AliasClientDb.Credential", "Credential")
.WithMany("Passwords")
.HasForeignKey("CredentialId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Credential");
});
modelBuilder.Entity("AliasClientDb.Alias", b =>
{
b.Navigation("Credentials");
});
modelBuilder.Entity("AliasClientDb.Credential", b =>
{
b.Navigation("Attachments");
b.Navigation("Passwords");
});
modelBuilder.Entity("AliasClientDb.Service", b =>
{
b.Navigation("Credentials");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,107 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AliasClientDb.Migrations
{
/// <inheritdoc />
public partial class _130UpdateIdentityStructure : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AddressCity",
table: "Aliases");
migrationBuilder.DropColumn(
name: "AddressCountry",
table: "Aliases");
migrationBuilder.DropColumn(
name: "AddressState",
table: "Aliases");
migrationBuilder.DropColumn(
name: "AddressStreet",
table: "Aliases");
migrationBuilder.DropColumn(
name: "AddressZipCode",
table: "Aliases");
migrationBuilder.DropColumn(
name: "BankAccountIBAN",
table: "Aliases");
migrationBuilder.DropColumn(
name: "Hobbies",
table: "Aliases");
migrationBuilder.DropColumn(
name: "PhoneMobile",
table: "Aliases");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "AddressCity",
table: "Aliases",
type: "VARCHAR",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "AddressCountry",
table: "Aliases",
type: "VARCHAR",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "AddressState",
table: "Aliases",
type: "VARCHAR",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "AddressStreet",
table: "Aliases",
type: "VARCHAR",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "AddressZipCode",
table: "Aliases",
type: "VARCHAR",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "BankAccountIBAN",
table: "Aliases",
type: "TEXT",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Hobbies",
table: "Aliases",
type: "TEXT",
maxLength: 255,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "PhoneMobile",
table: "Aliases",
type: "TEXT",
maxLength: 255,
nullable: true);
}
}
}

View File

@@ -27,30 +27,6 @@ namespace AliasClientDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("AddressCity")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("AddressCountry")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("AddressState")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("AddressStreet")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("AddressZipCode")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("BankAccountIBAN")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<DateTime>("BirthDate")
.HasColumnType("TEXT");
@@ -69,10 +45,6 @@ namespace AliasClientDb.Migrations
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("Hobbies")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<string>("LastName")
.HasMaxLength(255)
.HasColumnType("VARCHAR");
@@ -81,10 +53,6 @@ namespace AliasClientDb.Migrations
.HasMaxLength(255)
.HasColumnType("VARCHAR");
b.Property<string>("PhoneMobile")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");

View File

@@ -0,0 +1,96 @@
//-----------------------------------------------------------------------
// <copyright file="IdentityGeneratorTest.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasVault.Tests.Generators;
using System.Net.Mail;
using AliasGenerators.Identity.Implementations;
using AliasGenerators.Identity.Models;
/// <summary>
/// Tests for the CsvImportExport class.
/// </summary>
public class IdentityGeneratorTest
{
/// <summary>
/// Tests the generation of random dutch identities.
/// </summary>
/// <returns>Task.</returns>
[Test]
public async Task TestNlGenerator()
{
// Generate random NL identity.
var generator = IdentityGeneratorFactory.CreateIdentityGenerator("nl");
// Generate 10 identities, check if they are all unique.
var identities = new List<Identity>();
for (var i = 0; i < 10; i++)
{
var identity = await generator.GenerateRandomIdentityAsync();
Console.WriteLine($"Generated identity: {identity.FirstName} {identity.LastName} ({identity.Gender}) - {identity.BirthDate.ToShortDateString()} - {identity.NickName} - {identity.EmailPrefix}@domain.tld");
identities.Add(identity);
}
Assert.That(identities, Has.Count.EqualTo(10), "Should generate 10 identities");
Assert.That(
identities,
Is.All.Matches<Identity>(
i =>
!string.IsNullOrWhiteSpace(i.FirstName) && !string.IsNullOrWhiteSpace(i.LastName)),
"All identities should have non-empty first and last names");
Assert.That(identities, Is.Unique, "All identities should be unique");
foreach (var identity in identities)
{
var email = identity.EmailPrefix + "@domain.tld";
Assert.DoesNotThrow(
() =>
new MailAddress(email),
$"Email address '{email}' is not a valid email. Check email prefix generation logic.");
}
}
/// <summary>
/// Tests the generation of random english identities.
/// </summary>
/// <returns>Task.</returns>
[Test]
public async Task TestEnGenerator()
{
// Generate random EN identity.
var generator = IdentityGeneratorFactory.CreateIdentityGenerator("en");
// Generate 10 identities, check if they are all unique.
var identities = new List<Identity>();
for (var i = 0; i < 10; i++)
{
var identity = await generator.GenerateRandomIdentityAsync();
Console.WriteLine($"Generated identity: {identity.FirstName} {identity.LastName} ({identity.Gender}) - {identity.BirthDate.ToShortDateString()} - {identity.NickName} - {identity.EmailPrefix}@domain.tld");
identities.Add(identity);
}
Assert.That(identities, Has.Count.EqualTo(10), "Should generate 10 identities");
Assert.That(
identities,
Is.All.Matches<Identity>(
i =>
!string.IsNullOrWhiteSpace(i.FirstName) && !string.IsNullOrWhiteSpace(i.LastName)),
"All identities should have non-empty first and last names");
Assert.That(identities, Is.Unique, "All identities should be unique");
foreach (var identity in identities)
{
var email = identity.EmailPrefix + "@domain.tld";
Assert.DoesNotThrow(
() =>
new MailAddress(email),
$"Email address '{email}' is not a valid email. Check email prefix generation logic.");
}
}
}

View File

@@ -38,15 +38,7 @@ public class CsvImportExportTests
LastName = "Doe",
NickName = "JD",
BirthDate = new DateTime(1990, 1, 1, 0, 0, 0, DateTimeKind.Utc),
AddressStreet = "123 Main St",
AddressCity = "New York",
AddressState = "NY",
AddressZipCode = "12345",
AddressCountry = "USA",
Hobbies = "Reading, Writing",
Email = "johndoe",
PhoneMobile = "123-456-7890",
BankAccountIBAN = "US1234567890",
CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now,
},
@@ -93,15 +85,7 @@ public class CsvImportExportTests
Assert.That(importedCredential.Alias.LastName, Is.EqualTo(credential.Alias.LastName));
Assert.That(importedCredential.Alias.NickName, Is.EqualTo(credential.Alias.NickName));
Assert.That(importedCredential.Alias.BirthDate, Is.EqualTo(credential.Alias.BirthDate));
Assert.That(importedCredential.Alias.AddressStreet, Is.EqualTo(credential.Alias.AddressStreet));
Assert.That(importedCredential.Alias.AddressCity, Is.EqualTo(credential.Alias.AddressCity));
Assert.That(importedCredential.Alias.AddressState, Is.EqualTo(credential.Alias.AddressState));
Assert.That(importedCredential.Alias.AddressZipCode, Is.EqualTo(credential.Alias.AddressZipCode));
Assert.That(importedCredential.Alias.AddressCountry, Is.EqualTo(credential.Alias.AddressCountry));
Assert.That(importedCredential.Alias.Hobbies, Is.EqualTo(credential.Alias.Hobbies));
Assert.That(importedCredential.Alias.Email, Is.EqualTo(credential.Alias.Email));
Assert.That(importedCredential.Alias.PhoneMobile, Is.EqualTo(credential.Alias.PhoneMobile));
Assert.That(importedCredential.Alias.BankAccountIBAN, Is.EqualTo(credential.Alias.BankAccountIBAN));
Assert.That(importedCredential.Alias.CreatedAt.ToString("yyyy-MM-dd"), Is.EqualTo(credential.Alias.CreatedAt.ToString("yyyy-MM-dd")));
Assert.That(importedCredential.Alias.UpdatedAt.ToString("yyyy-MM-dd"), Is.EqualTo(credential.Alias.UpdatedAt.ToString("yyyy-MM-dd")));
Assert.That(importedCredential.ServiceId, Is.EqualTo(credential.ServiceId));

View File

@@ -40,15 +40,7 @@ public static class CredentialCsvService
AliasLastName = credential.Alias?.LastName ?? string.Empty,
AliasNickName = credential.Alias?.NickName ?? string.Empty,
AliasBirthDate = credential.Alias?.BirthDate,
AliasAddressStreet = credential.Alias?.AddressStreet ?? string.Empty,
AliasAddressCity = credential.Alias?.AddressCity ?? string.Empty,
AliasAddressState = credential.Alias?.AddressState ?? string.Empty,
AliasAddressZipCode = credential.Alias?.AddressZipCode ?? string.Empty,
AliasAddressCountry = credential.Alias?.AddressCountry ?? string.Empty,
AliasHobbies = credential.Alias?.Hobbies ?? string.Empty,
AliasEmail = credential.Alias?.Email ?? string.Empty,
AliasPhoneMobile = credential.Alias?.PhoneMobile ?? string.Empty,
AliasBankAccountIBAN = credential.Alias?.BankAccountIBAN ?? string.Empty,
AliasCreatedAt = credential.Alias?.CreatedAt,
AliasUpdatedAt = credential.Alias?.UpdatedAt,
ServiceId = credential.ServiceId,
@@ -111,15 +103,7 @@ public static class CredentialCsvService
LastName = record.AliasLastName,
NickName = record.AliasNickName,
BirthDate = record.AliasBirthDate ?? DateTime.MinValue,
AddressStreet = record.AliasAddressStreet,
AddressCity = record.AliasAddressCity,
AddressState = record.AliasAddressState,
AddressZipCode = record.AliasAddressZipCode,
AddressCountry = record.AliasAddressCountry,
Hobbies = record.AliasHobbies,
Email = record.AliasEmail,
PhoneMobile = record.AliasPhoneMobile,
BankAccountIBAN = record.AliasBankAccountIBAN,
CreatedAt = record.AliasCreatedAt ?? DateTime.UtcNow,
UpdatedAt = record.AliasUpdatedAt ?? DateTime.UtcNow
},
@@ -164,15 +148,7 @@ public class CredentialCsvRecord
public string AliasLastName { get; set; } = string.Empty;
public string AliasNickName { get; set; } = string.Empty;
public DateTime? AliasBirthDate { get; set; } = null;
public string AliasAddressStreet { get; set; } = string.Empty;
public string AliasAddressCity { get; set; } = string.Empty;
public string AliasAddressState { get; set; } = string.Empty;
public string AliasAddressZipCode { get; set; } = string.Empty;
public string AliasAddressCountry { get; set; } = string.Empty;
public string AliasHobbies { get; set; } = string.Empty;
public string AliasEmail { get; set; } = string.Empty;
public string AliasPhoneMobile { get; set; } = string.Empty;
public string AliasBankAccountIBAN { get; set; } = string.Empty;
public DateTime? AliasCreatedAt { get; set; } = null;
public DateTime? AliasUpdatedAt { get; set; } = null;
public Guid ServiceId { get; set; } = Guid.Empty;