// SPDX-FileCopyrightText: 2026 Progmasoft // SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 using static OpenIddict.Abstractions.OpenIddictConstants; namespace Progmasoft.OAuth; /// One permission an application can ask an account for. /// The scope value of the OAuth request. /// What the consent page tells the account holder the application will be able to do. /// /// The audience of the access tokens that carry the scope, or when only Progmasoft /// Credentials itself serves the scope. /// internal sealed record OAuthScope(string Name, string Consent, string? Resource); /// The scopes of Progmasoft OAuth. /// /// Each scope grants one thing, so that an application asks only for what it needs and the account holder sees each /// grant on its own line of the consent page. openid is not listed: it is the OpenID Connect request itself /// and grants nothing but the account identifier. /// internal static class OAuthScopes { /// The audience of the ViGet scopes; ViGet accepts only access tokens issued for it. public const string VigetResource = "viget"; /// Reading the packages the account has published. public const string VigetPackagesRead = "viget.packages.read"; /// Publishing packages under the account. public const string VigetPackagesPublish = "viget.packages.publish"; /// Yanking packages of the account. public const string VigetPackagesYank = "viget.packages.yank"; /// Every scope an application may request besides openid, in the order the consent page lists them. public static IReadOnlyList All { get; } = [ new(Scopes.Profile, "Read your Progmasoft account name.", null), new(Scopes.Email, "Read the email address you sign in and registered with.", null), new(VigetPackagesRead, "Read the packages you have published on ViGet.", VigetResource), new(VigetPackagesPublish, "Publish packages to ViGet under your account.", VigetResource), new(VigetPackagesYank, "Yank packages you have published on ViGet.", VigetResource), new(Scopes.OfflineAccess, "Keep this access when you are not signed in, until you revoke it.", null), ]; /// Finds a scope by its name. /// The scope value. /// The scope, or when Progmasoft OAuth has no such scope. public static OAuthScope? Find(string name) => All.FirstOrDefault(scope => scope.Name == name); /// The audiences of a set of scopes. /// Scope values that were granted. /// Each audience once. public static IEnumerable ResourcesOf(IEnumerable scopes) => scopes .Select(Find) .Where(scope => scope?.Resource is not null) .Select(scope => scope!.Resource!) .Distinct(StringComparer.Ordinal); }