Got a login

dotnet-7.0
Paul Schneider 1 year ago
parent 908d461552
commit b46c4b3447
61 changed files with 7793 additions and 609 deletions

@ -19,10 +19,10 @@ namespace Yavsc
public const string CompanyClaimType = "https://schemas.pschneider.fr/identity/claims/Company";
public const string UserNameRegExp = @"^[a-zA-Z][a-zA-Z0-9._-]*$";
public const string UserFileNamePatternRegExp = @"^([a-zA-Z0-9._-]*/)*[a-zA-Z0-9._-]+$";
public const string AuthorizePath = "~/authorize";
public const string TokenPath = "~/token";
public const string LoginPath = "~/signin";
public const string LogoutPath = "~/signout";
public const string AuthorizePath = "/authorize";
public const string TokenPath = "/token";
public const string LoginPath = "/signin";
public const string LogoutPath = "/signout";
public const string SignalRPath = "/api/signalr";

@ -1,19 +0,0 @@
using System.Threading.Tasks;
using Yavsc.Abstract.Manage;
namespace Yavsc.Services
{
public interface IEmailSender
{
/// <summary>
/// Sends en email.
/// </summary>
/// <param name="username">user name in database</param>
/// <param name="email">user's email</param>
/// <param name="subject">email subject</param>
/// <param name="message">message</param>
/// <returns>the message id</returns>
Task<EmailSentViewModel> SendEmailAsync(string username, string email, string subject, string message);
}
}

@ -9,11 +9,11 @@ using Yavsc.Models.Bank;
using Yavsc.Models.Access;
namespace Yavsc.Models
{
public class ApplicationUser : IdentityUser, IBaseTrackedEntity
[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser
{
/// <summary>
/// Another me, as a byte array.
/// <summary>
/// Another me, as a byte array.TG7@Eu%80rufzkhbb
/// This value points a picture that may be used
/// to present the user
/// </summary>
@ -113,24 +113,5 @@ namespace Yavsc.Models
[InverseProperty("Member")]
public virtual List<CircleMember> Membership { get; set; }
public DateTime DateCreated
{
get; set;
}
public string UserCreated
{
get; set;
}
public DateTime DateModified
{
get; set;
}
public string UserModified
{
get; set;
}
}
}

@ -1,7 +0,0 @@
namespace Yavsc.Server.Services
{
public class TranslationService
{
}
}

@ -1,7 +0,0 @@
namespace Yavsc
{
public class ThirdPartyFiles {
}
}

@ -10,8 +10,7 @@ namespace Yavsc.Server.Settings
new Dictionary<string, Func<ApplicationUser, bool>>
{
{ "allow-monthly", u => u.AllowMonthlyEmail },
{ "email-not-confirmed", u => !u.EmailConfirmed && u.DateCreated < DateTime.Now.AddDays(-7) },
{ "user-to-remove", u => !u.EmailConfirmed && u.DateCreated < DateTime.Now.AddDays(-14) }
{ "email-not-confirmed", u => !u.EmailConfirmed }
};
}
}

@ -6,14 +6,15 @@ using Yavsc.Attributes.Validation;
namespace Yavsc.ViewModels.Account
{
// TODO external autentication providers
public class SignInViewModel
public class SignInModel
{
/// <summary>
/// <summary>
/// Local user's name.
/// </summary>
/// <returns></returns>
[YaRequired]
public string UserName { get; set; }
public string EMail { get; set; }
/// <summary>
/// Local user's password .
@ -46,11 +47,6 @@ namespace Yavsc.ViewModels.Account
/// <returns></returns>
public string ReturnUrl { get; set; }
/// <summary>
/// Lists external identity provider descriptions.
/// </summary>
/// <returns>an enumeration of the descriptions.</returns>
public IEnumerable<YaAuthenticationDescription> ExternalProviders { get; set; }
}
public class YaAuthenticationDescription {

@ -18,7 +18,5 @@ namespace Yavsc.ViewModels.Account
[Display(Name = "Confirmer le mot de passe")]
[Compare("Password", ErrorMessage = "Le mot de passe et sa confirmation ne sont pas les mêmes.")]
public string ConfirmPassword { get; set; }
public string Code { get; set; }
}
}

@ -24,20 +24,20 @@ namespace Yavsc.Controllers
// GET: api/ApplicationUserApi
[HttpGet]
public IEnumerable<UserInfo> GetApplicationUser()
public IEnumerable<UserInfo> GetApplicationUser(int skip=0, int take = 25)
{
return _context.Users.OrderByDescending(u => u.DateModified).Take(25)
.Select(u=> new UserInfo {
return _context.Users.Skip(skip).Take(take)
.Select(u=> new UserInfo{
UserId = u.Id,
UserName = u.UserName,
Avatar = u.Avatar });
Avatar = u.Avatar});
}
[HttpGet("search/{pattern}")]
public IEnumerable<UserInfo> SearchApplicationUser(string pattern)
public IEnumerable<UserInfo> SearchApplicationUser(string pattern, int skip=0, int take = 25)
{
return _context.Users.Where(u => u.UserName.Contains(pattern))
.OrderByDescending(u => u.DateModified).Take(25)
.Skip(skip).Take(take)
.Select(u=> new UserInfo {
UserId = u.Id,
UserName = u.UserName,

@ -1,3 +1,4 @@
using System.Web;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
@ -13,6 +14,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Yavsc.Helpers;
using Yavsc.Abstract.Manage;
using Microsoft.AspNetCore.Identity.UI.Services;
using Yavsc.Interface;
namespace Yavsc.Controllers
{
@ -23,7 +26,7 @@ namespace Yavsc.Controllers
private const int defaultLen = 10;
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ITrueEmailSender _emailSender;
// private readonly ISmsSender _smsSender;
private readonly ILogger _logger;
readonly SiteSettings _siteSettings;
@ -39,7 +42,7 @@ namespace Yavsc.Controllers
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ITrueEmailSender emailSender,
IOptions<SiteSettings> siteSettings,
ILoggerFactory loggerFactory, IOptions<TwilioSettings> twilioSettings,
IStringLocalizer<Yavsc.YavscLocalisation> localizer,
@ -65,12 +68,9 @@ namespace Yavsc.Controllers
}
[Authorize(Roles = Constants.AdminGroupName)]
[Route("Account/UserList/{page?}/{len?}")]
public async Task<IActionResult> UserList(string page, string len)
[Route("Account/UserList/{pageNum}/{len?}")]
public async Task<IActionResult> UserList(int pageNum, int pageLen = defaultLen)
{
int pageNum = page!=null ? int.Parse(page) : 0;
int pageLen = len!=null ? int.Parse(len) : defaultLen;
var users = _dbContext.Users.OrderBy(u=>u.UserName);
var shown = pageNum * pageLen;
var toShow = users.Skip(shown).Take(pageLen);
@ -96,7 +96,7 @@ namespace Yavsc.Controllers
// will be redirected to after a successful authentication and not
// the redirect_uri of the requesting client application against the third
// party identity provider.
return View(new SignInViewModel
return View(new SignInModel
{
ReturnUrl = returnUrl ?? "/",
});
@ -122,16 +122,17 @@ namespace Yavsc.Controllers
[AllowAnonymous]
[HttpPost(Constants.LoginPath)]
public async Task<IActionResult> SignIn(SignInViewModel model)
public async Task<IActionResult> SignIn(SignInModel model)
{
if (Request.Method == "POST")
if (Request.Method == "POST") // "hGbkk9B94NAae#aG"
{
if (model.Provider ==null || model.Provider == "LOCAL")
{
if (ModelState.IsValid)
{
var user = _dbContext.Users.Include(u=>u.Membership).FirstOrDefault(
u=>u.UserName == model.UserName);
u=>u.Email == model.EMail);
if (user != null)
{
@ -149,7 +150,7 @@ namespace Yavsc.Controllers
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
var result = await _signInManager.PasswordSignInAsync(model.EMail, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
@ -171,7 +172,7 @@ namespace Yavsc.Controllers
}
else
{
ModelState.AddModelError(string.Empty, $"Invalid login attempt. ({model.UserName}, {model.Password})");
ModelState.AddModelError(string.Empty, $"Invalid login attempt. ({model.EMail}, {model.Password})");
return this.ViewOk(model);
}
}
@ -245,19 +246,11 @@ namespace Yavsc.Controllers
// Send an email with this link
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, protocol: "https", host: Startup.Authority);
var emailSent = await _emailSender.SendEmailAsync(model.UserName, model.Email, _localizer["ConfirmYourAccountTitle"],
await _emailSender.SendEmailAsync(model.UserName, model.Email, _localizer["ConfirmYourAccountTitle"],
string.Format(_localizer["ConfirmYourAccountBody"], _siteSettings.Title, callbackUrl, _siteSettings.Slogan, _siteSettings.Audience));
// No, wait for more than a login pass submission:
// do not await _signInManager.SignInAsync(user, isPersistent: false);
if (emailSent==null)
{
_logger.LogWarning("User created with error sending email confirmation request");
this.NotifyWarning(
"E-mail confirmation",
_localizer["ErrorSendingEmailForConfirm"]
);
}
else
this.NotifyInfo(
"E-mail confirmation",
_localizer["EmailSentForConfirm"]
@ -305,7 +298,7 @@ namespace Yavsc.Controllers
string.Format(this._localizer["ConfirmYourAccountBody"],
_siteSettings.Title, callbackUrl, _siteSettings.Slogan,
_siteSettings.Audience));
return res;
return new EmailSentViewModel { EMail = user.Email, Sent = true, MessageId = res };
}
private async Task<EmailSentViewModel> SendEMailFactorAsync(ApplicationUser user, string provider)
@ -318,7 +311,7 @@ namespace Yavsc.Controllers
string.Format(this._localizer["AccountEmailFactorBody"],
_siteSettings.Title, callbackUrl, _siteSettings.Slogan,
_siteSettings.Audience, code));
return res;
return new EmailSentViewModel { EMail = user.Email, Sent = true, MessageId = res };;
}
//
// POST: /Account/LogOff
@ -553,10 +546,12 @@ namespace Yavsc.Controllers
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
// Send an email with this link
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code },
protocol: "https", host: Startup.Authority);
var callbackUrl = _siteSettings.Audience + "/Account/ResetPassword/" +
HttpUtility.UrlEncode(user.Id) + "/" + HttpUtility.UrlEncode(code);
var sent = await _emailSender.SendEmailAsync(user.UserName, user.Email, _localizer["Reset Password"],
_localizer["Please reset your password by following this link:"] + " <" + callbackUrl + ">");
_localizer["Please reset your password by "] + " <a href=\"" +
callbackUrl + "\" >following this link</a>");
return View("ForgotPasswordConfirmation", sent);
}
@ -574,21 +569,23 @@ namespace Yavsc.Controllers
}
// GET: /Account/ResetPassword
[HttpGet]
[HttpGet("/Account/ResetPassword/{id}/{code}")]
[AllowAnonymous]
public async Task<IActionResult> ResetPassword(string UserId)
public async Task<IActionResult> ResetPassword(string id, string code)
{
var user = await _userManager.FindByIdAsync(UserId);
var user = await _userManager.FindByIdAsync(id);
if (user==null) return new BadRequestResult();
// We just serve the form to reset here.
return View();
return View(new ResetPasswordViewModel { });
}
// POST: /Account/ResetPassword
[HttpPost]
[HttpPost("/Account/ResetPassword/{id}/{code}")]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
public async Task<IActionResult> ResetPassword([FromRoute] string id,
[FromRoute] string code,
ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
@ -600,7 +597,9 @@ namespace Yavsc.Controllers
// Don't reveal that the user does not exist
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
}
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
// code : "CfDJ8DmPlC3R8%2fNMqGlHZHZMwbjaXxgD3GW3H75Ubt+4Sbw%2fn%2fdg9X8Bll+CLIh%2fquI+Z96XEkx7bfrZiB+wpPb+b5%2ffgzgy+cQnKfX9J7%2fLNro+F3uE5JkXSlUc1WqVW2mVQrpWHjx1Dbn2n77TTGym3ttQoECsTR%2foo27dW9U11pmRJuTiwPBJZBOt0ffIRmgDDHh2f0VySTQEwjfRiLdCwctL%2fmh21ympJMKJl5PZnTVs"
var result = await _userManager.ResetPasswordAsync(user,
HttpUtility.UrlDecode(code), model.Password);
if (result.Succeeded)
{

@ -14,6 +14,7 @@ using Yavsc.ViewModels.Calendar;
using Yavsc.Models;
using Yavsc.Services;
using Yavsc.ViewModels.Manage;
using Microsoft.AspNetCore.Identity.UI.Services;
namespace Yavsc.Controllers
{

@ -7,6 +7,7 @@ using Microsoft.Extensions.Localization;
namespace Yavsc.Controllers
{
using Helpers;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Models;
@ -14,6 +15,8 @@ namespace Yavsc.Controllers
using Models.Relationship;
using Models.Workflow;
using Services;
using Yavsc.Interface;
using Yavsc.Settings;
public class CommandController : Controller
{
@ -21,7 +24,7 @@ namespace Yavsc.Controllers
protected ApplicationDbContext _context;
protected GoogleAuthSettings _googleSettings;
protected IYavscMessageSender _MessageSender;
protected IEmailSender _emailSender;
protected ITrueEmailSender _emailSender;
protected IStringLocalizer _localizer;
protected SiteSettings _siteSettings;
protected SmtpSettings _smtpSettings;
@ -33,7 +36,7 @@ namespace Yavsc.Controllers
UserManager<ApplicationUser> userManager,
ICalendarManager calendarManager,
IStringLocalizer<Yavsc.YavscLocalisation> localizer,
IEmailSender emailSender,
ITrueEmailSender emailSender,
IOptions<SmtpSettings> smtpSettings,
IOptions<SiteSettings> siteSettings,
ILoggerFactory loggerFactory)

@ -22,6 +22,9 @@ namespace Yavsc.Controllers
using PayPal.PayPalAPIInterfaceService.Model;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.UI.Services;
using Yavsc.Interface;
using Yavsc.Settings;
public class HairCutCommandController : CommandController
{
@ -32,7 +35,7 @@ namespace Yavsc.Controllers
IYavscMessageSender GCMSender,
UserManager<ApplicationUser> userManager,
IStringLocalizer<Yavsc.YavscLocalisation> localizer,
IEmailSender emailSender,
ITrueEmailSender emailSender,
IOptions<SmtpSettings> smtpSettings,
IOptions<SiteSettings> siteSettings,
ICalendarManager calManager,

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<key id="ab1c0839-2078-41c1-b8be-72fa977278d4" version="1">
<creationDate>2023-04-05T20:58:19.6046151Z</creationDate>
<activationDate>2023-04-05T20:58:19.598076Z</activationDate>
<expirationDate>2023-07-04T20:58:19.598076Z</expirationDate>
<descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
<descriptor>
<encryption algorithm="AES_256_CBC" />
<validation algorithm="HMACSHA256" />
<masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
<!-- Warning: the key below is in an unencrypted form. -->
<value>fc3m/BUIbMxSbIjZ7fBO4iIiQZVjA5IVlrEFCwBsBJDvYbJJkaCphoeP15iJEsd2Zv3x946xfNyo+c+9WU2xoQ==</value>
</masterKey>
</descriptor>
</descriptor>
</key>

@ -0,0 +1,15 @@
namespace Yavsc.Interface
{
public interface ITrueEmailSender
{
//
// Résumé :
// This API supports the ASP.NET Core Identity default UI infrastructure and is
// not intended to be used directly from your code. This API may change or be removed
// in future releases.
Task<string> SendEmailAsync(string name, string email, string subject, string htmlMessage);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,219 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class userreload : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Activities_Activities_ParentCode",
table: "Activities");
migrationBuilder.DropForeignKey(
name: "FK_AspNetUsers_BankIdentity_BankInfoId",
table: "AspNetUsers");
migrationBuilder.DropForeignKey(
name: "FK_AspNetUsers_Locations_PostalAddressId",
table: "AspNetUsers");
migrationBuilder.DropIndex(
name: "IX_AspNetUsers_BankInfoId",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "BankInfoId",
table: "AspNetUsers");
migrationBuilder.Sql("delete from \"BankIdentity\"");
migrationBuilder.AddColumn<string>(
name: "UserId",
table: "BankIdentity",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AlterColumn<long>(
name: "PostalAddressId",
table: "AspNetUsers",
type: "bigint",
nullable: true,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "AspNetUsers",
type: "character varying(256)",
maxLength: 256,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "DedicatedGoogleCalendar",
table: "AspNetUsers",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512);
migrationBuilder.AlterColumn<string>(
name: "ParentCode",
table: "Activities",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddUniqueConstraint(
name: "AK_AspNetUsers_Email",
table: "AspNetUsers",
column: "Email");
migrationBuilder.CreateIndex(
name: "IX_BankIdentity_UserId",
table: "BankIdentity",
column: "UserId");
migrationBuilder.AddForeignKey(
name: "FK_Activities_Activities_ParentCode",
table: "Activities",
column: "ParentCode",
principalTable: "Activities",
principalColumn: "Code");
migrationBuilder.AddForeignKey(
name: "FK_AspNetUsers_Locations_PostalAddressId",
table: "AspNetUsers",
column: "PostalAddressId",
principalTable: "Locations",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_BankIdentity_AspNetUsers_UserId",
table: "BankIdentity",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Activities_Activities_ParentCode",
table: "Activities");
migrationBuilder.DropForeignKey(
name: "FK_AspNetUsers_Locations_PostalAddressId",
table: "AspNetUsers");
migrationBuilder.DropForeignKey(
name: "FK_BankIdentity_AspNetUsers_UserId",
table: "BankIdentity");
migrationBuilder.DropIndex(
name: "IX_BankIdentity_UserId",
table: "BankIdentity");
migrationBuilder.DropUniqueConstraint(
name: "AK_AspNetUsers_Email",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "UserId",
table: "BankIdentity");
migrationBuilder.AlterColumn<long>(
name: "PostalAddressId",
table: "AspNetUsers",
type: "bigint",
nullable: false,
defaultValue: 0L,
oldClrType: typeof(long),
oldType: "bigint",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "AspNetUsers",
type: "character varying(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256);
migrationBuilder.AlterColumn<string>(
name: "DedicatedGoogleCalendar",
table: "AspNetUsers",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AddColumn<long>(
name: "BankInfoId",
table: "AspNetUsers",
type: "bigint",
nullable: false,
defaultValue: 0L);
migrationBuilder.AlterColumn<string>(
name: "ParentCode",
table: "Activities",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUsers_BankInfoId",
table: "AspNetUsers",
column: "BankInfoId");
migrationBuilder.AddForeignKey(
name: "FK_Activities_Activities_ParentCode",
table: "Activities",
column: "ParentCode",
principalTable: "Activities",
principalColumn: "Code",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AspNetUsers_BankIdentity_BankInfoId",
table: "AspNetUsers",
column: "BankInfoId",
principalTable: "BankIdentity",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AspNetUsers_Locations_PostalAddressId",
table: "AspNetUsers",
column: "PostalAddressId",
principalTable: "Locations",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,42 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Yavsc.Migrations
{
/// <inheritdoc />
public partial class nullableFullname : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "FullName",
table: "AspNetUsers",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512);
migrationBuilder.Sql("update \"AspNetUsers\" SET \"UserName\" = \"Email\";");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "FullName",
table: "AspNetUsers",
type: "character varying(512)",
maxLength: 512,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
}
}
}

@ -294,9 +294,6 @@ namespace Yavsc.Migrations
.HasColumnType("character varying(512)")
.HasDefaultValue("/images/Users/icon_user.png");
b.Property<long>("BankInfoId")
.HasColumnType("bigint");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
@ -308,7 +305,6 @@ namespace Yavsc.Migrations
.HasColumnType("timestamp with time zone");
b.Property<string>("DedicatedGoogleCalendar")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
@ -321,6 +317,7 @@ namespace Yavsc.Migrations
.HasColumnType("bigint");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
@ -328,7 +325,6 @@ namespace Yavsc.Migrations
.HasColumnType("boolean");
b.Property<string>("FullName")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
@ -359,7 +355,6 @@ namespace Yavsc.Migrations
.HasColumnType("boolean");
b.Property<long?>("PostalAddressId")
.IsRequired()
.HasColumnType("bigint");
b.Property<string>("SecurityStamp")
@ -382,7 +377,7 @@ namespace Yavsc.Migrations
b.HasKey("Id");
b.HasIndex("BankInfoId");
b.HasAlternateKey("Email");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
@ -547,12 +542,18 @@ namespace Yavsc.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("WicketCode")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("BankIdentity");
});
@ -2099,7 +2100,6 @@ namespace Yavsc.Migrations
.HasColumnType("text");
b.Property<string>("ParentCode")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Photo")
@ -2685,19 +2685,9 @@ namespace Yavsc.Migrations
modelBuilder.Entity("Yavsc.Models.ApplicationUser", b =>
{
b.HasOne("Yavsc.Models.Bank.BankIdentity", "BankInfo")
.WithMany()
.HasForeignKey("BankInfoId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Yavsc.Models.Relationship.Location", "PostalAddress")
.WithMany()
.HasForeignKey("PostalAddressId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("BankInfo");
.HasForeignKey("PostalAddressId");
b.Navigation("PostalAddress");
});
@ -2713,6 +2703,17 @@ namespace Yavsc.Migrations
b.Navigation("Balance");
});
modelBuilder.Entity("Yavsc.Models.Bank.BankIdentity", b =>
{
b.HasOne("Yavsc.Models.ApplicationUser", "User")
.WithMany("BankInfo")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Yavsc.Models.Billing.CommandLine", b =>
{
b.HasOne("Yavsc.Models.Billing.Estimate", null)
@ -3231,9 +3232,7 @@ namespace Yavsc.Migrations
{
b.HasOne("Yavsc.Models.Workflow.Activity", "Parent")
.WithMany("Children")
.HasForeignKey("ParentCode")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("ParentCode");
b.Navigation("Parent");
});
@ -3434,6 +3433,8 @@ namespace Yavsc.Migrations
b.Navigation("AccountBalance")
.IsRequired();
b.Navigation("BankInfo");
b.Navigation("BlackList");
b.Navigation("Book");

@ -52,10 +52,14 @@ namespace Yavsc.Models
builder.Entity<DeviceDeclaration>().Property(x => x.DeclarationDate).HasDefaultValueSql("LOCALTIMESTAMP");
builder.Entity<BlogTag>().HasKey(x => new { x.PostId, x.TagId });
builder.Entity<ApplicationUser>().Property(u => u.FullName).IsRequired(false);
builder.Entity<ApplicationUser>().Property(u => u.DedicatedGoogleCalendar).IsRequired(false);
builder.Entity<ApplicationUser>().HasMany<ChatConnection>(c => c.Connections);
builder.Entity<ApplicationUser>().Property(u => u.Avatar).HasDefaultValue(Constants.DefaultAvatar);
builder.Entity<ApplicationUser>().Property(u => u.DiskQuota).HasDefaultValue(Constants.DefaultFSQ);
builder.Entity<ApplicationUser>().HasAlternateKey(u => u.Email);
builder.Entity<BlackListed>().HasOne<ApplicationUser>(bl => bl.User);
builder.Entity<BlackListed>().HasOne<ApplicationUser>(bl => bl.Owner);
builder.Entity<UserActivity>().HasKey(u => new { u.DoesCode, u.UserId });
builder.Entity<Instrumentation>().HasKey(u => new { u.InstrumentId, u.UserId });
builder.Entity<CircleAuthorizationToBlogPost>().HasKey(a => new { a.CircleId, a.BlogPostId });
@ -67,8 +71,6 @@ namespace Yavsc.Models
builder.Entity<Models.Cratie.Option>().HasKey(o => new { o.Code, o.CodeScrutin });
builder.Entity<Notification>().Property(n => n.icon).HasDefaultValue("exclam");
builder.Entity<ChatRoomAccess>().HasKey(p => new { room = p.ChannelName, user = p.UserId });
builder.Entity<BlackListed>().HasOne<ApplicationUser>(bl => bl.User);
builder.Entity<BlackListed>().HasOne<ApplicationUser>(bl => bl.Owner);
builder.Entity<BlogTrad>().HasKey(tr => new { post = tr.PostId, lang = tr.Lang });
builder.Entity<InstrumentRating>().HasAlternateKey(i => new { Instrument= i.InstrumentId, owner = i.OwnerId });

@ -0,0 +1,3 @@
Support for ASP.NET Core Identity was added to your project.
For setup and configuration information, see https://go.microsoft.com/fwlink/?linkid=2116645.

@ -15,6 +15,7 @@ using System.Reflection;
using Yavsc.Abstract.Templates;
using Microsoft.AspNetCore.Identity;
using RazorEngine.Configuration;
using Yavsc.Interface;
namespace Yavsc.Lib
{
@ -30,16 +31,14 @@ namespace Yavsc.Lib
readonly IStringLocalizer<EMailer> stringLocalizer;
readonly ApplicationDbContext dbContext;
readonly IEmailSender mailSender;
readonly ILogger logger;
public EMailer(ApplicationDbContext context, IEmailSender sender,
public EMailer(ApplicationDbContext context,
IStringLocalizer<EMailer> localizer,
ILoggerFactory loggerFactory)
{
stringLocalizer = localizer;
mailSender = sender;
logger = loggerFactory.CreateLogger<EMailer>();

@ -1,3 +1,4 @@
using System.Text;
using System;
using System.Net;
using System.Threading.Tasks;
@ -7,10 +8,13 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MimeKit;
using Yavsc.Abstract.Manage;
using Microsoft.AspNetCore.Identity.UI.Services;
using Yavsc.Interface;
using Yavsc.Settings;
namespace Yavsc.Services
{
public class MailSender : IEmailSender
public class MailSender : IEmailSender, ITrueEmailSender
{
readonly SiteSettings siteSettings;
readonly SmtpSettings smtpSettings;
@ -22,10 +26,9 @@ namespace Yavsc.Services
ILoggerFactory loggerFactory
)
{
siteSettings = sitesOptions?.Value;
smtpSettings = smtpOptions?.Value;
siteSettings = sitesOptions.Value;
smtpSettings = smtpOptions.Value;
logger = loggerFactory.CreateLogger<MailSender>();
}
/// <summary>
@ -39,52 +42,42 @@ namespace Yavsc.Services
/// </returns>
public async Task<EmailSentViewModel> SendEmailAsync(string username, string email, string subject, string message)
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
{
EmailSentViewModel model = new EmailSentViewModel{ EMail = email };
try
await SendEmailAsync("", email, subject, htmlMessage);
}
public async Task<string> SendEmailAsync(string name, string email, string subject, string htmlMessage)
{
logger.LogInformation($"SendEmail for {email} : {subject}");
MimeMessage msg = new ();
msg.From.Add(new MailboxAddress(siteSettings.Owner.Name,
siteSettings.Owner.EMail));
msg.To.Add(new MailboxAddress(name, email));
msg.Body = new TextPart("html")
{
logger.LogInformation($"sendEmail for {email} : {message}");
MimeMessage msg = new MimeMessage();
msg.From.Add(new MailboxAddress(
siteSettings.Owner.Name,
siteSettings.Owner.EMail));
msg.To.Add(new MailboxAddress(username, email));
msg.Body = new TextPart("plain")
{
Text = message
};
msg.Subject = subject;
msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
siteSettings.Authority
);
using (SmtpClient sc = new SmtpClient())
{
sc.Connect(
smtpSettings.Host,
smtpSettings.Port,
SecureSocketOptions.Auto);
if (smtpSettings.UserName!=null) {
NetworkCredential creds = new NetworkCredential(
smtpSettings.UserName, smtpSettings.Password, smtpSettings.Domain);
await sc.AuthenticateAsync(System.Text.Encoding.UTF8, creds, System.Threading.CancellationToken.None);
}
await sc.SendAsync(msg);
model.MessageId = msg.MessageId;
model.Sent = true; // a duplicate info to remove from the view model, that equals to MessageId == null
logger.LogInformation($"Sent : {msg}");
}
}
catch (Exception ex)
Text = htmlMessage
};
msg.Subject = subject;
msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
siteSettings.Authority
);
using (SmtpClient sc = new ())
{
model.Sent = false;
model.ErrorMessage = ex.Message;
return model;
sc.Connect(
smtpSettings.Server,
smtpSettings.Port,
SecureSocketOptions.Auto);
if (smtpSettings.UserName!=null) {
NetworkCredential creds = new (
smtpSettings.UserName, smtpSettings.Password);
await sc.AuthenticateAsync(System.Text.Encoding.UTF8, creds, System.Threading.CancellationToken.None);
}
await sc.SendAsync(msg);
logger.LogInformation($"Sent : {msg.MessageId}");
}
return model;
return msg.MessageId;
}
}
}

@ -1,6 +1,8 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Yavsc.Interface;
using Yavsc.Interfaces.Workflow;
using Yavsc.Models;
using Yavsc.Models.Google.Messaging;
@ -12,7 +14,7 @@ namespace Yavsc.Services
public class YavscMessageSender : IYavscMessageSender
{
private readonly ILogger _logger;
readonly IEmailSender _emailSender;
readonly ITrueEmailSender _emailSender;
readonly SiteSettings siteSettings;
readonly ApplicationDbContext _dbContext;
readonly IConnexionManager _cxManager;
@ -21,7 +23,7 @@ namespace Yavsc.Services
public YavscMessageSender(
ILoggerFactory loggerFactory,
IOptions<SiteSettings> sitesOptions,
IEmailSender emailSender,
ITrueEmailSender emailSender,
ApplicationDbContext dbContext,
IConnexionManager cxManager,
IHubContext<ChatHub> hubContext
@ -90,24 +92,12 @@ namespace Yavsc.Services
_logger.LogDebug($"Sending to {user.UserName} <{user.Email}> : {body}");
var mailSent = await _emailSender.SendEmailAsync(
user.UserName,
user.Email,
result.message_id = await _emailSender.SendEmailAsync(user.UserName, user.Email,
$"{ev.Sender} (un client) vous demande un rendez-vous",
body + Environment.NewLine
);
if (!mailSent.Sent)
{
result.message_id = mailSent.MessageId;
result.error = mailSent.ErrorMessage;
response.failure++;
}
else
{
result.message_id = mailSent.MessageId;
body + Environment.NewLine);
response.success++;
}
var cxids = _cxManager.GetConnexionIds(user.UserName);
if (cxids == null)
{

@ -1,15 +1,13 @@
namespace Yavsc
namespace Yavsc.Settings
{
public class SmtpSettings
{
public string Host { get; set; }
public string Server { get; set; }
public int Port { get; set; }
public string SenderName { get; set; }
public string SenderEmail { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Domain { get; set; }
public bool EnableSSL { get; set; }
}
}
}

@ -0,0 +1,8 @@
namespace Yavsc
{
public class DataProtectionSettings
{
public Dictionary<string,string> Keys { get; set; }
public int ExpiresInHours { get; set; }
}
}

@ -1,84 +0,0 @@
using System;
using System.IO;
using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
namespace Yavsc
{
class YaSendFileWrapper : IHttpResponseBodyFeature
{
private readonly Stream _output;
private readonly ILogger _logger;
internal YaSendFileWrapper(Stream output, ILogger logger)
{
_output = output;
_logger = logger;
}
public async Task SendFileAsync(string fileName, long offset, long? length, CancellationToken cancel)
{
cancel.ThrowIfCancellationRequested();
if (string.IsNullOrWhiteSpace(fileName))
{
throw new ArgumentNullException("fileName");
}
if (!File.Exists(fileName))
{
throw new FileNotFoundException(string.Empty, fileName);
}
FileInfo fileInfo = new FileInfo(fileName);
if (offset < 0 || offset > fileInfo.Length)
{
throw new ArgumentOutOfRangeException("offset", offset, string.Empty);
}
if (length.HasValue && (length.Value < 0 || length.Value > fileInfo.Length - offset))
{
throw new ArgumentOutOfRangeException("length", length, string.Empty);
}
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, maxbufferlen, FileOptions.Asynchronous | FileOptions.SequentialScan);
try
{
fileStream.Seek(offset, SeekOrigin.Begin);
_logger.LogInformation(string.Format("Copying bytes range:{0},{1} filename:{2} ", offset, (!length.HasValue) ? null : (offset + length), fileName));
// await CopyToAsync(fileStream, _output, length, cancel);
await CopyToAsync(fileStream, _output);
}
finally
{
fileStream.Dispose();
}
}
private const int maxbufferlen = 65536;
public Stream Stream => throw new NotImplementedException();
public PipeWriter Writer => throw new NotImplementedException();
private async Task CopyToAsync(FileStream fileStream, Stream output)
{
await Task.Run(() => fileStream.CopyTo(output, maxbufferlen));
}
public void DisableBuffering()
{
throw new NotImplementedException();
}
public Task StartAsync(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task CompleteAsync()
{
throw new NotImplementedException();
}
}
}

@ -7,30 +7,6 @@ using Yavsc.ViewModels.Auth;
namespace Yavsc
{
public static class YaFileSServerExtenstions
{
public static IApplicationBuilder UseYaFileServer(this IApplicationBuilder builder, FileServerOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (options.EnableDefaultFiles)
{
builder = builder.UseDefaultFiles(options.DefaultFilesOptions);
}
if (options.EnableDirectoryBrowsing)
{
builder = builder.UseDirectoryBrowser(options.DirectoryBrowserOptions);
}
return builder.UseYaSendFileFallback().UseStaticFiles(options.StaticFileOptions);
}
public static IApplicationBuilder UseYaSendFileFallback(this IApplicationBuilder builder)
{
return builder.UseMiddleware<YaSendFileMiddleware>(new object[0]);
}
}
public partial class Startup
{

@ -11,13 +11,15 @@ using Newtonsoft.Json;
using Google.Apis.Util.Store;
using Microsoft.Extensions.Localization;
using Yavsc.Helpers;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Yavsc.Models;
using Yavsc.Services;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Identity;
using Yavsc.Interface;
using Yavsc.Settings;
using Microsoft.AspNetCore.DataProtection;
namespace Yavsc
{
@ -29,6 +31,7 @@ namespace Yavsc
public static string Authority { get; private set; }
public static string Temp { get; set; }
public static SiteSettings SiteSetup { get; private set; }
public SmtpSettings SmtpSetup { get; private set; }
public static GoogleServiceAccount GServiceAccount { get; private set; }
public static string HostingFullName { get; set; }
@ -38,38 +41,39 @@ namespace Yavsc
public Startup( IWebHostEnvironment env)
public Startup(IWebHostEnvironment env)
{
AppDomain.CurrentDomain.UnhandledException += OnUnHandledException;
var devtag = env.IsDevelopment() ? "D" : "";
var prodtag = env.IsProduction() ? "P" : "";
var stagetag = env.IsStaging() ? "S" : "";
string devtag = env.IsDevelopment() ? "D" : "";
string prodtag = env.IsProduction() ? "P" : "";
string stagetag = env.IsStaging() ? "S" : "";
HostingFullName = $"{env.EnvironmentName} [{prodtag}/{devtag}/{stagetag}]";
// Set up configuration sources.
var builder = new ConfigurationBuilder()
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
_ = builder.AddEnvironmentVariables();
Configuration = builder.Build();
var auth = Configuration["Site:Authority"];
var cxstr = Configuration["ConnectionStrings:Default"];
ConnectionString = cxstr;
ConnectionString = Configuration["ConnectionStrings:Default"];
AppDomain.CurrentDomain.SetData(Constants.YavscConnectionStringEnvName, ConnectionString);
var googleClientFile = Configuration["Authentication:Google:GoogleWebClientJson"];
var googleServiceAccountJsonFile = Configuration["Authentication:Google:GoogleServiceAccountJson"];
string? googleClientFile = Configuration["Authentication:Google:GoogleWebClientJson"];
string? googleServiceAccountJsonFile = Configuration["Authentication:Google:GoogleServiceAccountJson"];
if (googleClientFile != null)
{
GoogleWebClientConfiguration = new ConfigurationBuilder().AddJsonFile(googleClientFile).Build();
}
if (googleServiceAccountJsonFile != null)
{
var safile = new FileInfo(googleServiceAccountJsonFile);
FileInfo safile = new FileInfo(googleServiceAccountJsonFile);
GServiceAccount = JsonConvert.DeserializeObject<GoogleServiceAccount>(safile.OpenText().ReadToEnd());
}
}
@ -89,23 +93,24 @@ namespace Yavsc
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
// Database connection
services.AddOptions();
var siteSettings = Configuration.GetSection("Site");
services.Configure<SiteSettings>(siteSettings);
var smtpSettings = Configuration.GetSection("Smtp");
services.Configure<SmtpSettings>(smtpSettings);
var googleSettings = Configuration.GetSection("Authentication").GetSection("Google");
services.Configure<GoogleAuthSettings>(googleSettings);
var cinfoSettings = Configuration.GetSection("Authentication").GetSection("Societeinfo");
services.Configure<CompanyInfoSettings>(cinfoSettings);
var oauthFacebookSettings = Configuration.GetSection("Authentication").GetSection("Facebook");
services.Configure<FacebookOAuth2AppSettings>(oauthFacebookSettings);
var paypalSettings = Configuration.GetSection("Authentication").GetSection("PayPal");
services.Configure<PayPalSettings>(paypalSettings);
IConfigurationSection siteSettings = Configuration.GetSection("Site");
_ = services.Configure<SiteSettings>(siteSettings);
IConfigurationSection smtpSettings = Configuration.GetSection("Smtp");
_ = services.Configure<SmtpSettings>(smtpSettings);
IConfigurationSection protectionSettings = Configuration.GetSection("DataProtection");
_ = services.Configure<DataProtectionSettings>(smtpSettings);
IConfigurationSection googleSettings = Configuration.GetSection("Authentication").GetSection("Google");
_ = services.Configure<GoogleAuthSettings>(googleSettings);
IConfigurationSection cinfoSettings = Configuration.GetSection("Authentication").GetSection("Societeinfo");
_ = services.Configure<CompanyInfoSettings>(cinfoSettings);
IConfigurationSection oauthFacebookSettings = Configuration.GetSection("Authentication").GetSection("Facebook");
_ = services.Configure<FacebookOAuth2AppSettings>(oauthFacebookSettings);
IConfigurationSection paypalSettings = Configuration.GetSection("Authentication").GetSection("PayPal");
_ = services.Configure<PayPalSettings>(paypalSettings);
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<SiteSettings>), typeof(OptionsManager<SiteSettings>)));
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<SmtpSettings>), typeof(OptionsManager<SmtpSettings>)));
@ -113,17 +118,17 @@ namespace Yavsc
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<CompanyInfoSettings>), typeof(OptionsManager<CompanyInfoSettings>)));
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<RequestLocalizationOptions>), typeof(OptionsManager<RequestLocalizationOptions>)));
services.Add(ServiceDescriptor.Singleton(typeof(IDiskUsageTracker), typeof(DiskUsageTracker)));
services.Configure<RequestLocalizationOptions>(options =>
_ = services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en"),
new CultureInfo("fr"),
new CultureInfo("pt")
};
var supportedUICultures = new[]
CultureInfo[] supportedUICultures = new[]
{
new CultureInfo("fr"),
new CultureInfo("en"),
@ -145,56 +150,36 @@ namespace Yavsc
};
});
// Add framework services.
services.AddEntityFrameworkNpgsql()
.AddDbContext<ApplicationDbContext>();
services.AddCors(
services.AddSignalR();
services.AddOptions();
options =>
{
options.AddPolicy("CorsPolicy", builder =>
_ = services.AddCors(options =>
{
builder.WithOrigins("*");
options.AddPolicy("CorsPolicy", builder =>
{
_ = builder.WithOrigins("*");
});
});
}
);
// Add session related services.
services.AddSession();
// Add the system clock service
services.AddSingleton<ISystemClock, SystemClock>();
_ = services.AddSingleton<ISystemClock, SystemClock>();
services.AddAuthorization(options =>
{
_ = services.AddSingleton<IConnexionManager, HubConnectionManager>();
_ = services.AddSingleton<ILiveProcessor, LiveProcessor>();
_ = services.AddSingleton<IFileSystemAuthManager, FileSystemAuthManager>();
options.AddPolicy("AdministratorOnly", policy =>
{
policy.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", Constants.AdminGroupName);
});
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
options.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes("yavsc")
.RequireAuthenticatedUser().Build());
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
});
services.AddAuthentication("Bearer").AddJwtBearer("Bearer", options =>
{
options.Authority = siteSettings.GetValue<string>("ExternalUrl");
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
// Add framework services.
/* FIXME services.AddSingleton<IAuthorizationHandler, HasBadgeHandler>();
/*services.AddSingleton<IAuthorizationHandler, HasBadgeHandler>();
services.AddSingleton<IAuthorizationHandler, HasTemporaryPassHandler>();
services.AddSingleton<IAuthorizationHandler, BlogEditHandler>();
services.AddSingleton<IAuthorizationHandler, BlogViewHandler>();
@ -202,13 +187,18 @@ namespace Yavsc
services.AddSingleton<IAuthorizationHandler, BillViewHandler>();
services.AddSingleton<IAuthorizationHandler, PostUserFileHandler>();
services.AddSingleton<IAuthorizationHandler, ViewFileHandler>();
services.AddSingleton<IAuthorizationHandler, SendMessageHandler>(); */
services.AddSingleton<IConnexionManager, HubConnectionManager>();
services.AddSingleton<ILiveProcessor, LiveProcessor>();
services.AddSingleton<IFileSystemAuthManager, FileSystemAuthManager>();
services.AddSingleton<IAuthorizationHandler, SendMessageHandler>();*/
_ = services.AddDbContext<ApplicationDbContext>()
.AddIdentity<ApplicationUser, IdentityRole>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultUI()
.AddDefaultTokenProviders();
services.AddMvc(config =>
_ = services.AddMvc(config =>
{
/* var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
@ -231,31 +221,64 @@ namespace Yavsc
options.ResourcesPath = "Resources";
}).AddDataAnnotationsLocalization();
// services.AddScoped<LanguageActionFilter>();
// Inject ticket formatting
services.AddTransient(typeof(ISecureDataFormat<>), typeof(SecureDataFormat<>));
services.AddTransient<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>();
services.AddTransient<ISecureDataFormat<AuthenticationTicket>, TicketDataFormat>();
// services.AddTransient(typeof(ISecureDataFormat<>), typeof(SecureDataFormat<>));
// services.AddTransient<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>();
// services.AddTransient<ISecureDataFormat<AuthenticationTicket>, TicketDataFormat>();
// Add application services.
services.AddTransient<IEmailSender, MailSender>();
services.AddTransient<IYavscMessageSender, YavscMessageSender>();
services.AddTransient<IBillingService, BillingService>();
services.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false));
services.AddTransient<ICalendarManager, CalendarManager>();
_ = services.AddTransient<ITrueEmailSender, MailSender>();
_ = services.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, MailSender>();
_ = services.AddTransient<IYavscMessageSender, YavscMessageSender>();
_ = services.AddTransient<IBillingService, BillingService>();
_ = services.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false));
_ = services.AddTransient<ICalendarManager, CalendarManager>();
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
services.AddLocalization(options =>
_ = services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
var datadi = new DirectoryInfo(protectionSettings.GetSection("Keys").GetValue<string>("Dir"));
// Add session related services.
services.AddSession();
services.AddDataProtection().PersistKeysToFileSystem(datadi);
services.AddAuthorization(options =>
{
options.AddPolicy("AdministratorOnly", policy =>
{
_ = policy.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", Constants.AdminGroupName);
});
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
options.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes("Bearer")
.RequireAuthenticatedUser().Build());
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = siteSettings.GetValue<string>("Authority");
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
_ = services.AddControllersWithViews()
.AddNewtonsoftJson();
}
@ -263,12 +286,13 @@ namespace Yavsc
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(
IApplicationBuilder app,
IApplicationBuilder app,
IOptions<SiteSettings> siteSettings,
IOptions<SmtpSettings> smtpSettings,
IAuthorizationService authorizationService,
IOptions<PayPalSettings> payPalSettings,
IOptions<GoogleAuthSettings> googleSettings,
IStringLocalizer<Yavsc.YavscLocalisation> localizer,
IStringLocalizer<YavscLocalisation> localizer,
ILoggerFactory loggerFactory,
IWebHostEnvironment env)
{
@ -276,47 +300,52 @@ namespace Yavsc
GoogleSettings = googleSettings.Value;
ResourcesHelpers.GlobalLocalizer = localizer;
SiteSetup = siteSettings.Value;
SmtpSetup = smtpSettings.Value;
Authority = siteSettings.Value.Authority;
var blogsDir = siteSettings.Value.Blog;
if (blogsDir == null) throw new Exception("blogsDir is not set.");
var billsDir = siteSettings.Value.Bills;
if (billsDir == null) throw new Exception("billsDir is not set.");
string blogsDir = siteSettings.Value.Blog ?? throw new Exception("blogsDir is not set.");
string billsDir = siteSettings.Value.Bills ?? throw new Exception("billsDir is not set.");
AbstractFileSystemHelpers.UserFilesDirName = new DirectoryInfo(blogsDir).FullName;
AbstractFileSystemHelpers.UserBillsDirName = new DirectoryInfo(billsDir).FullName;
Temp = siteSettings.Value.TempDir;
PayPalSettings = payPalSettings.Value;
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
// TODO implement an installation & upgrade procedure
// Create required directories
foreach (string dir in new string[] { AbstractFileSystemHelpers.UserFilesDirName, AbstractFileSystemHelpers.UserBillsDirName, SiteSetup.TempDir })
{
if (dir == null) throw new Exception(nameof(dir));
if (dir == null)
{
throw new Exception(nameof(dir));
}
DirectoryInfo di = new DirectoryInfo(dir);
if (!di.Exists) di.Create();
DirectoryInfo di = new(dir);
if (!di.Exists)
{
di.Create();
}
}
_logger = loggerFactory.CreateLogger<Startup>();
app.UseStatusCodePagesWithReExecute("/Home/Status/{0}");
_ = app.UseStatusCodePagesWithReExecute("/Home/Status/{0}");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWelcomePage("/welcome");
_ = app.UseDeveloperExceptionPage();
_ = app.UseWelcomePage("/welcome");
app.UseMigrationsEndPoint();
}
else
{
// For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
app.UseExceptionHandler("/Home/Error");
_ = app.UseExceptionHandler("/Home/Error");
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>()
.Database.Migrate();
}
using IServiceScope serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope();
serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>()
.Database.Migrate();
}
catch (TargetInvocationException ex)
{
@ -325,32 +354,38 @@ namespace Yavsc
{
// TODO (or not) Hit the developper
}
else throw ex;
else
{
throw ex;
}
}
}
// before fixing the security protocol, let beleive our lib it's done with it.
var cxmgr = PayPal.Manager.ConnectionManager.Instance;
// _ = PayPal.Manager.ConnectionManager.Instance;
// then, fix it.
// ServicePointManager.SecurityProtocol = (SecurityProtocolType)0xC00; // Tls12, required by PayPal
app.UseSession();
// _ = app.UseSession();
ConfigureFileServerApp(app, SiteSetup, env, authorizationService);
app.UseRequestLocalization();
_ = app.UseRequestLocalization();
ConfigureWorkflow();
ConfigureWebSocketsApp(app);
_logger.LogInformation("LocalApplicationData: " + Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.DoNotVerify));
CheckApp(env, loggerFactory);
app.UseStatusCodePages().UseStaticFiles().UseAuthentication();
app.UseMvcWithDefaultRoute();
app.UseSession();
_ = app.UseStatusCodePages().UseStaticFiles().UseAuthentication();
_ = app.UseMvcWithDefaultRoute();
}
}

@ -1,6 +0,0 @@
namespace Yavsc
{
internal class UserTokenProvider
{
}
}

@ -1,54 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
namespace Yavsc
{
public class YaSendFileMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
//
// Résumé :
// Creates a new instance of the SendFileMiddleware.
//
// Paramètres :
// next:
// The next middleware in the pipeline.
//
// loggerFactory:
// An Microsoft.Extensions.Logging.ILoggerFactory instance used to create loggers.
public YaSendFileMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
if (loggerFactory == null)
{
throw new ArgumentNullException("loggerFactory");
}
_next = next;
_logger = loggerFactory.CreateLogger<YaSendFileMiddleware>();
}
public Task Invoke(HttpContext context)
{
if (context.Response.StatusCode < 400 || context.Response.StatusCode >= 600 )
{
if (context.Features.Get<YaSendFileWrapper>() == null)
{
context.Features.Set(new YaSendFileWrapper(context.Response.Body, _logger));
}
}
return _next(context);
}
}
}

@ -6,7 +6,7 @@
<h2>@ViewData["Title"]</h2>
<form asp-controller="Account" asp-action="ForgotPassword" method="post" class="form-horizontal" role="form">
<h4>Enter your user name or e-mail."]</h4>
<h4>Enter your user name or e-mail.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">

@ -4,5 +4,5 @@
<h2>@ViewData["Title"].</h2>
<p>
PleaseCheckYourEmail"]
PleaseCheckYourEmail
</p>

@ -9,7 +9,6 @@
<h4>Reset your password.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Code" type="hidden" />
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">

@ -34,7 +34,7 @@
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Change password</button>
<a asp-action="ForgotPassword" asp-controller="Account">Forgot your password?"]</a>
<a asp-action="ForgotPassword" asp-controller="Account">Forgot your password?</a>
</div>
</div>
</form>

@ -1,7 +1,7 @@

@using Yavsc.ViewModels.Account
@model SignInViewModel
@model SignInModel
@{
ViewData["Title"] = "Log in";
}
@ -11,20 +11,19 @@
<hr/>
<h2 class="lead text-left">Use a local account to log in</h2>
<form action="@Constants.LoginPath" method="post" class="form-horizontal" role="form">
<form asp-action="SignIn" class="form-horizontal" role="form">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label for="UserName" class="col-md-2 control-label">UserName</label>
<label for="EMail" class="col-md-2 control-label">EMail</label>
<div class="col-md-10">
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
<input asp-for="EMail" class="form-control" autocomplete="email" aria-required="true" placeholder="name@example.com" />
<span asp-validation-for="EMail" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label for="Password" class="col-md-2 control-label">Password</label>
<div class="col-md-10">
<input asp-for="Password" class="form-control" />
<input asp-for="Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
@ -45,7 +44,7 @@
<a asp-action="Register" asp-controller="Account">Register as a new user?</a>
</p>
<p>
<a asp-action="ForgotPassword" asp-controller="Account">Forgot your password?"]</a>
<a asp-action="ForgotPassword" asp-controller="Account">Forgot your password</a>
</p>
<input type="hidden" name="Provider" value="LOCAL" />
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
@ -55,25 +54,5 @@
<hr/>
<h2 class="lead text-left">Use another service to log in:</h2>
@if (Model.ExternalProviders==null || Model.ExternalProviders.Count() == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="http://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
@foreach (var description in Model.ExternalProviders) {
<form action="@Constants.LoginPath" method="post">
<input type="hidden" name="Provider" value="@description.AuthenticationScheme" />
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
<button class="btn btn-lg btn-success" type="submit" name="Submit.Login">Connect using @description.DisplayName</button>
@Html.AntiForgeryToken()
</form>
}
}
</div>

@ -1,54 +1,62 @@
@using System.Security.Claims
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@if (User.IsSignedIn())
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<ul class="nav navbar-nav navbar-right">
<li>
<a asp-controller="Manage" class="navbar-link" asp-action="Index" title="Manage">
<img src="/Avatars/@(User.GetUserName()).xs.png" asp-append-version="true" class="smalltofhol" />
</a>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Plateforme <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a asp-controller="Bug" asp-action="Index">Bugs</a></li>
<li><a asp-controller="HyperLink" asp-action="Index">HyperLink</a></li>
<li><a asp-controller="LiveFlow" asp-action="Index">LiveFlow</a></li>
<li><a asp-controller="Feature" asp-action="Index">Features</a></li>
</ul>
@if (User.IsInRole(Constants.AdminGroupName)) {
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Administration <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a asp-controller="Administration" asp-action="Index">Index</a></li>
<li><a asp-controller="Activity" asp-action="Index">Activités</a></li>
<li><a asp-controller="CommandForms" asp-action="Index">Formulaires</a></li>
<li><a asp-controller="Notifications" asp-action="Index">Notifications</a></li>
<li><a asp-controller="SIRENExceptions" asp-action="Index">Excéptions au numéro de SIREN</a></li>
<li><a asp-controller="Client" asp-action="Index">Accès API</a></li>
<li><a asp-controller="MailingTemplate" asp-action="Index">Emailing</a></li>
</ul>
</li>}
<li>
<a asp-controller="Manage" class="navbar-link" asp-action="Index" title="Manage">
<img src="/Avatars/@(User.GetUserName()).xs.png" asp-append-version="true" class="smalltofhol" />
</a>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Plateforme <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a asp-controller="Bug" asp-action="Index">Bugs</a></li>
<li><a asp-controller="HyperLink" asp-action="Index">HyperLink</a></li>
<li><a asp-controller="LiveFlow" asp-action="Index">LiveFlow</a></li>
<li><a asp-controller="Feature" asp-action="Index">Features</a></li>
</ul>
</li>
@if (User.IsInRole(Constants.AdminGroupName)) {
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Administration <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a asp-controller="Administration" asp-action="Index">Index</a></li>
<li><a asp-controller="Activity" asp-action="Index">Activités</a></li>
<li><a asp-controller="CommandForms" asp-action="Index">Formulaires</a></li>
<li><a asp-controller="Notifications" asp-action="Index">Notifications</a></li>
<li><a asp-controller="SIRENExceptions" asp-action="Index">Excéptions au numéro de SIREN</a></li>
<li><a asp-controller="Client" asp-action="Index">Accès API</a></li>
<li><a asp-controller="MailingTemplate" asp-action="Index">Emailing</a></li>
</ul>
</li>}
<li>
<form asp-controller="Account" asp-action="LogOff"
method="post" id="logoutForm">
<button type="submit" class="btn navbar-btn" >Logout</button>
<input type="hidden" name="ReturnUrl" value="/" />
</form>
</li>
</ul>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @UserManager.GetUserName(User)!</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="ApiKeys" asp-action="Index" title="Api Keys">Your API keys</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })">
<button type="submit" class="nav-link btn btn-link">Logout</button>
</form>
</li>
}
else
{
<ul class="nav navbar-nav navbar-right">
<li><a class="navbar-link" asp-controller="Account" asp-action="Register" asp-route-returnurl="@Url.Action()" >Register</a></li>
<li><a class="navbar-link" asp-controller="Account" asp-action="SignIn" asp-route-returnurl="@Url.Action()" >Login</a></li>
</ul>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>

@ -4,6 +4,7 @@
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
@ -18,7 +19,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.4" />
<PackageReference Include="Google.Apis.Compute.v1" Version="1.60.0.2987" />
<PackageReference Include="MarkdownDeep-av.NET" Version="1.5.27" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
@ -27,10 +31,12 @@
<PackageReference Include="MimeKit" Version="3.6.0" />
<PackageReference Include="pazof.rules" Version="1.1.3" />
<PackageReference Include="RazorEngine.NetCore" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.5" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="7.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.4" IncludeAssets="All" />
</ItemGroup>
<ItemGroup>

@ -35,7 +35,7 @@
},
"DataProtection": {
"Keys": {
"Dir": "DataProtection-Keys"
"Dir": "DataProtection"
},
"RSAParamFile": "RSA-Params.json",
"ExpiresInHours": 168

@ -458,7 +458,7 @@ namespace yavscTests
// before fixing the security protocol, let beleive our lib it's done with it.
//var cxmgr = PayPal.Manager.ConnectionManager.Instance;
// then, fix it.
ServicePointManager.SecurityProtocol = (SecurityProtocolType)0xC00; // Tls12, required by PayPal
// ServicePointManager.SecurityProtocol = (SecurityProtocolType)0xC00; // Tls12, required by PayPal
app.UseIISPlatformHandler(options =>
{

@ -1,19 +0,0 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"ansi-to-html": {
"version": "0.6.9",
"resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.9.tgz",
"integrity": "sha512-hwNdg2DNgCzsrvaNc+LDqSxJkpxf9oEt4R7KE0IeURXhEOlontEqNpXNiGeFBpSes8TZF+ZZ9sjB85QzjPsI6A==",
"requires": {
"entities": "^1.1.1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
}
}
}
Loading…