Skip to content

Commit

Permalink
Add arbitrary yaml metadata from tier as sponsor claims
Browse files Browse the repository at this point in the history
As part of the tier description, sponsorables can add arbitrary yaml metadata such as:

```
<!-- tier: basic -->
```

Multiple values are supported in standard yaml format.

These claims are cumulative (i.e. tier 3 gets tier 2 and tier 1 metadata, with the closest tier to the actual sponsoring tier wins).

This now allows client code to selectively enable functionality based on GH sponsorship tier metadata.

Fixes #234
  • Loading branch information
kzu committed Oct 1, 2024
1 parent 2df40e0 commit 8da7b38
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 10 deletions.
22 changes: 13 additions & 9 deletions src/Core/SponsorsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -298,16 +298,16 @@ await sponsorable.QueryAsync(GraphQueries.SponsoringOrganizationsForUser(account
return null;

var manifest = await GetManifestAsync();
SponsorTypes sponsor;
SponsorTypes types;

using (var activity = ActivityTracer.Source.StartActivity("Sponsor.Lookup"))
{
sponsor = await GetSponsorTypeAsync(principal);
types = await GetSponsorTypeAsync(principal);
// coma-separated list of types can be parsed easily with parse_csv
activity?.SetTag("Type", sponsor.ToString().Replace(" ", ""));
activity?.SetTag("Type", types.ToString().Replace(" ", ""));
}

if (sponsor == SponsorTypes.None)
if (types == SponsorTypes.None)
return null;

if (principal?.FindFirst("urn:github:login")?.Value is not string login)
Expand All @@ -325,17 +325,21 @@ await sponsorable.QueryAsync(GraphQueries.SponsoringOrganizationsForUser(account
// check for each flags SponsorTypes and add claims accordingly
// Note that in JWT IANA, roles is plural, unlike the more common role (singular) in claims-based auth.
// See https://www.iana.org/assignments/jwt/jwt.xhtml
if (sponsor.HasFlag(SponsorTypes.Team))
if (types.HasFlag(SponsorTypes.Team))
claims.Add(new("roles", "team"));
if (sponsor.HasFlag(SponsorTypes.Organization))
if (types.HasFlag(SponsorTypes.Organization))
claims.Add(new("roles", "org"));
if (sponsor.HasFlag(SponsorTypes.User))
if (types.HasFlag(SponsorTypes.User))
claims.Add(new("roles", "user"));
if (sponsor.HasFlag(SponsorTypes.Contributor))
if (types.HasFlag(SponsorTypes.Contributor))
claims.Add(new("roles", "contrib"));
if (sponsor.HasFlag(SponsorTypes.OpenSource))
if (types.HasFlag(SponsorTypes.OpenSource))
claims.Add(new("roles", "oss"));

var sponsor = await FindSponsorAsync(login);
if (sponsor is not null)
claims.AddRange(sponsor.Tier.Meta.Select(x => new Claim(x.Key, x.Value)));

// Use shorthand JWT claim for emails. See https://www.iana.org/assignments/jwt/jwt.xhtml
claims.AddRange(principal.Claims.Where(x => x.Type == ClaimTypes.Email).Select(x => new Claim(JwtRegisteredClaimNames.Email, x.Value)));

Expand Down
5 changes: 5 additions & 0 deletions src/Tests/SponsorManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,5 +359,10 @@ public async Task GetTierForLogin(string login, string tier, SponsorTypes type)
Assert.True(sponsor.Tier.Meta.TryGetValue("tier", out var existing));
Assert.Equal(tier, existing);
Assert.Equal(type, sponsor.Kind);

var claims = await manager.GetSponsorClaimsAsync(new ClaimsPrincipal(new ClaimsIdentity([new("urn:github:login", login)], "github")));

Assert.NotNull(claims);
Assert.Contains(claims, claim => claim.Type == "tier" && claim.Value == tier);
}
}
2 changes: 1 addition & 1 deletion src/Web/Stats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public async Task<HttpResponseData> NuGetCountAsync([HttpTrigger(AuthorizationLe
if (req.Query.Count == 1)
{
// Sum all packages across all repositories contributed to by the author in the querystring
if (req.Query.ToString() is { } author &&
if (req.Query.ToString() is { } author &&
stats.Authors.TryGetValue(author, out var repositories))
{
count = stats.Packages
Expand Down

0 comments on commit 8da7b38

Please sign in to comment.