Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Core/Resgrid.Config/ApiConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public static class ApiConfig
/// to the API and eventing hubs, on top of the configured base urls, their subdomains and
/// their shared parent domain (see Resgrid.Config.CorsHelper). Entries with a scheme match
/// the exact origin ("http://localhost:8081"); bare hosts match that host on any scheme and
/// port ("dispatch.example.com"). A single "*" allows every origin — intended only for
/// port ("dispatch.example.com"); wildcard hosts match the apex and every subdomain on any
/// scheme and port ("*.resgrid.com"). A single "*" allows every origin — intended only for
/// isolated on-prem or development installs.
/// </summary>
public static string CorsAllowedOrigins = "";
Expand Down
48 changes: 45 additions & 3 deletions Core/Resgrid.Config/CorsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ namespace Resgrid.Config
/// An origin is allowed when it matches any of:
/// 1. An entry in <see cref="ApiConfig.CorsAllowedOrigins"/>. Entries with a scheme
/// ("http://localhost:8081") must match the origin's scheme, host and port exactly; bare
/// hosts ("dispatch.example.com") match that host on any scheme/port. A single "*" entry
/// allows every origin and is intended only for isolated on-prem or development installs.
/// hosts ("dispatch.example.com") match that host on any scheme/port; wildcard hosts
/// ("*.resgrid.com") match the apex and every subdomain on any scheme/port. An entry equal
/// to the raw Origin header value also matches verbatim, which covers desktop-app origins
/// like Electron's "app://." that are not standard URIs. A single "*" entry allows every
/// origin and is intended only for isolated on-prem or development installs.
/// 2. The host of one of the configured base urls (ResgridBaseUrl, ResgridApiBaseUrl,
/// ResgridEventingBaseUrl), or any subdomain of one of those hosts.
/// 3. The widest safe parent domain of a base-url host, or any subdomain of it. This is what
Expand Down Expand Up @@ -82,7 +85,16 @@ public static class CorsHelper
/// </summary>
public static bool IsAllowedOrigin(string origin)
{
if (String.IsNullOrWhiteSpace(origin) || !Uri.TryCreate(origin, UriKind.Absolute, out var originUri) || String.IsNullOrWhiteSpace(originUri.Host))
if (String.IsNullOrWhiteSpace(origin))
return false;

// Verbatim config match before URI parsing: desktop-app origins such as
// Electron's custom-scheme "app://." are not reliably parseable as absolute
// URIs, so an exact entry must be honored without going through Uri.
if (MatchesConfiguredOriginVerbatim(origin))
return true;

if (!Uri.TryCreate(origin, UriKind.Absolute, out var originUri) || String.IsNullOrWhiteSpace(originUri.Host))
return false;

if (MatchesConfiguredOrigin(originUri))
Expand All @@ -109,6 +121,25 @@ public static bool IsAllowedOrigin(string origin)
return false;
}

private static bool MatchesConfiguredOriginVerbatim(string origin)
{
var configured = ApiConfig.CorsAllowedOrigins;
if (String.IsNullOrWhiteSpace(configured))
return false;

foreach (var rawEntry in configured.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
var entry = rawEntry.Trim();
if (entry.Length == 0)
continue;

if (entry == "*" || String.Equals(entry, origin, StringComparison.OrdinalIgnoreCase))
return true;
}

return false;
}

private static bool MatchesConfiguredOrigin(Uri originUri)
{
var configured = ApiConfig.CorsAllowedOrigins;
Expand All @@ -124,6 +155,17 @@ private static bool MatchesConfiguredOrigin(Uri originUri)
if (entry == "*")
return true;

if (entry.StartsWith("*.", StringComparison.Ordinal))
{
// Wildcard host: "*.resgrid.com" allows the apex and every subdomain,
// on any scheme and port.
var suffix = entry.Substring(2);
if (suffix.Length > 0 && HostMatchesOrIsSubdomainOf(originUri.Host, suffix))
return true;

continue;
}

if (entry.Contains("://"))
{
if (Uri.TryCreate(entry, UriKind.Absolute, out var entryUri) &&
Expand Down
10 changes: 10 additions & 0 deletions Core/Resgrid.Framework/Logging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@

}

public static void LogWarning(string message)
{
Initialize(null);


if (_logger != null)
_logger.Warning(message);

}

public static void LogDebug(string message)
{
Initialize(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>يُرجى ملاحظة أن البيانات المقدمة إلى Resgrid لقسم ما تخص ذلك القسم وقد تخضع لسياسات الاحتفاظ بالبيانات والقوانين السارية في نطاق القسم. سيؤدي حذف حسابك إلى مسح معلوماتك الشخصية (PII) وحذف بيانات تسجيل الدخول، لكنه لن يمسح جميع البيانات. ستحتاج إلى تقديم طلب إلى القسم الذي كنت منتمياً إليه إذا كنت تريد مسح جميع البيانات.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>سيؤدي حذف حسابك إلى إلغاء تنشيطه في جميع الأقسام التي أنت عضو فيها، وليس فقط القسم الحالي. ستتم إزالة جميع الأتمتة المجدولة الخاصة بك (تسليم التقارير، وتغييرات الحالة المجدولة، وتغييرات التوظيف المجدولة)، وستتوقف عن تلقي الإشعارات والمراسلات من جميع الأقسام.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>لا يمكنك حذف حسابك لأنك مالك قسم. إذا كنت ترغب في حذف القسم، ستحتاج إلى الوصول إليه عبر صفحة إعدادات القسم. إذا كنت تريد الاحتفاظ بالقسم، فاختر شخصاً آخر ليكون مالكاً للقسم ثم حاول حذف حسابك مرة أخرى.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>Wenn Sie Ihr Konto löschen, wird es in JEDER Abteilung deaktiviert, in der Sie Mitglied sind - nicht nur in Ihrer aktuellen. Alle Ihre geplanten Automatisierungen (Berichtszustellungen, geplante Statusänderungen und geplante Besetzungsänderungen) werden entfernt, und Sie erhalten keine Benachrichtigungen und Mitteilungen mehr von allen Abteilungen.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>Deleting your account will deactivate it in EVERY department you are a member of, not just your current one. All of your scheduled automations (report deliveries, scheduled status changes and scheduled staffing changes) will be removed, and you will stop receiving notifications and communications from all departments.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Ten en cuenta que los datos suministrados a Resgrid para un departamento son propiedad de ese departamento y pueden estar sujetos a políticas de retención de datos. Eliminar tu cuenta aquí borrará tu información personal (PII) y tu acceso, pero no todos los datos.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>Eliminar su cuenta la desactivará en TODOS los departamentos de los que sea miembro, no solo en el actual. Todas sus automatizaciones programadas (entregas de informes, cambios de estado programados y cambios de personal programados) serán eliminadas, y dejará de recibir notificaciones y comunicaciones de todos los departamentos.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>No puedes eliminar tu cuenta porque eres propietario de un departamento. Si deseas eliminar el departamento, debes acceder a eso a través de la página de configuración del departamento. Si deseas conservar el departamento, elige a otra persona como propietario del departamento y luego intenta eliminar tu cuenta.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>La suppression de votre compte le désactivera dans TOUS les départements dont vous êtes membre, pas seulement dans votre département actuel. Toutes vos automatisations planifiées (envois de rapports, changements de statut planifiés et changements d'effectifs planifiés) seront supprimées, et vous ne recevrez plus de notifications ni de communications d'aucun département.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>L'eliminazione del tuo account lo disattiverà in TUTTI i dipartimenti di cui sei membro, non solo in quello corrente. Tutte le tue automazioni pianificate (invii di report, cambi di stato pianificati e modifiche pianificate del personale) verranno rimosse e smetterai di ricevere notifiche e comunicazioni da tutti i dipartimenti.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>Usunięcie konta spowoduje jego dezaktywację w KAŻDYM dziale, którego jesteś członkiem, nie tylko w bieżącym. Wszystkie zaplanowane automatyzacje (dostarczanie raportów, zaplanowane zmiany statusu i zaplanowane zmiany obsady) zostaną usunięte, a Ty przestaniesz otrzymywać powiadomienia i komunikaty ze wszystkich działów.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>Om du raderar ditt konto inaktiveras det i ALLA avdelningar du är medlem i, inte bara din nuvarande. Alla dina schemalagda automatiseringar (rapportleveranser, schemalagda statusändringar och schemalagda bemanningsändringar) tas bort, och du slutar få aviseringar och meddelanden från alla avdelningar.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<data name="DeleteAreYouSure3" xml:space="preserve">
<value>Please note, data supplied to Resgrid for a department is owned by that department and could be subject to data retention policies and laws governing the jurisdiction of the department. Deleting your account here will clear your PII (Personally Identifiable Information) and delete your login but won’t clear all data. You will need to make a request to the department you were apart of for additional if you want all data cleared.</value>
</data>
<data name="DeleteAreYouSure4" xml:space="preserve">
<value>Видалення облікового запису деактивує його в УСІХ підрозділах, учасником яких ви є, а не лише в поточному. Усі ваші заплановані автоматизації (доставка звітів, заплановані зміни статусу та заплановані зміни укомплектування) будуть видалені, і ви більше не отримуватимете сповіщення та повідомлення від жодного підрозділу.</value>
</data>
<data name="DepartmentOwnerError" xml:space="preserve">
<value>You are unable to delete your account because you are a Department Owner in a department. If you wish to delete the department you will need to access that though the Department Settings page. If you want to retain the department please choose another person as the Department Owner and then try and delete your account again.</value>
</data>
Expand Down
14 changes: 14 additions & 0 deletions Core/Resgrid.Model/Repositories/IScheduledTasksRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Resgrid.Model.Repositories
Expand All @@ -18,5 +19,18 @@ public interface IScheduledTasksRepository: IRepository<ScheduledTask>
Task<IEnumerable<ScheduledTask>> GetAllActiveTasksForTypesAsync(List<int> types);

Task<IEnumerable<ScheduledTask>> GetAllUpcomingOrRecurringReportDeliveryTasksAsync();

/// <summary>
/// Deletes every scheduled task (and their logs) owned by a user, across all departments.
/// Used when a user account is deleted/deactivated.
/// </summary>
Task<bool> DeleteAllTasksForUserAsync(string userId, CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Deletes every scheduled task (and their logs) owned by a user that is scoped to a single
/// department. Legacy rows with DepartmentId = 0 are left alone; the active-task queries
/// resolve those through non-deleted department memberships.
/// </summary>
Task<bool> DeleteAllTasksForUserInDepartmentAsync(string userId, int departmentId, CancellationToken cancellationToken = default(CancellationToken));
}
}
15 changes: 13 additions & 2 deletions Core/Resgrid.Model/Services/IDeleteService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ namespace Resgrid.Model.Services
public interface IDeleteService
{
/// <summary>
/// Deletes the user asynchronous.
/// Removes a user from a department (admin initiated). If the user belongs to other
/// departments only this department's access, roles, groups, lists and automations are
/// revoked and the account stays usable; if this is their only department the whole
/// account is deactivated using the same flow as the self-service account delete.
/// </summary>
/// <param name="departmentId">The department identifier.</param>
/// <param name="authorizingUserId">The authorizing user identifier.</param>
/// <param name="userIdToDelete">The user identifier to delete.</param>
/// <returns>Task&lt;DeleteUserResults&gt;.</returns>
Task<DeleteUserResults> DeleteUserAsync(int departmentId, string authorizingUserId, string userIdToDelete);
Task<DeleteUserResults> DeleteUserAsync(int departmentId, string authorizingUserId, string userIdToDelete, CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Revokes a user's access to a single department without touching their account, login
/// or PII: removes roles, group memberships, distribution list subscriptions and scheduled
/// automations for that department, then soft-deletes the membership. No authorization
/// check is performed; callers are responsible for authorizing the operation.
/// </summary>
Task<bool> RevokeDepartmentAccessAsync(string userId, int departmentId, string revokingUserId, CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Deletes the group asynchronous.
Expand Down
Loading
Loading