using Invercargill; using Invercargill.Mapping; using Invercargill.DataStructures; using InvercargillJson; namespace Spry.Authorisation { /** * Data structure embedded in authorisation tokens. * * Token contents (JSON, encrypted and signed): * - id: Identity unique identifier * - username: Human-readable name * - permissions: Array of permission strings * - data: Additional variant data * - issued_at: Token issuance timestamp * - expires_at: Token expiry timestamp */ public class AuthorisationToken { // Identity fields public Element user_identifier { get; private set; } public string username { get; private set; } public ImmutableLot permissions { get; private set; } public DateTime issued_at { get; private set; } public DateTime expires_at { get; private set; } public string token_id { get; private set; } public Properties data { get; private set; } public ByteBuffer cryptographic_token { get; internal set; } /** * Creates a token from an Identity. * * @param identity The identity to create a token for * @param duration Optional token duration (defaults to 24 hours) */ internal AuthorisationToken(Identity identity, TimeSpan? duration = null) { this.user_identifier = identity.identifier; this.username = identity.username; this.permissions = identity.permissions; this.data = identity.data; this.issued_at = new DateTime.now_utc(); this.expires_at = new DateTime.now_utc().add(duration ?? TimeSpan.HOUR * 24); this.token_id = Uuid.string_random(); } /** * Checks if the token has expired. * * @return true if the token has expired, false otherwise */ public bool has_expired() { return expires_at.compare(new DateTime.now_utc()) <= 0; } // Blank constructor for mapper below private AuthorisationToken.blank() { } /** * Gets the property mapper for AuthorisationToken serialization. * * Uses the PropertyMapper system from Invercargill.Mapping for * consistent serialization with the rest of the framework. */ public static PropertyMapper get_mapper() { return PropertyMapper.build_for(cfg => { cfg.map("uid", o => o.user_identifier, (o, v) => o.user_identifier = v); cfg.map("unm", o => o.username, (o, v) => o.username = v); cfg.map_many("prm", o => o.permissions, (o, v) => o.permissions = v.to_immutable_buffer()) .when_null(o => o.permissions = Iterate.nothing().to_immutable_buffer()); cfg.map("dat", o => o.data, (o, v) => o.data = v); cfg.map("iat", o => o.issued_at.format_iso8601(), (o, v) => o.issued_at = new DateTime.from_iso8601(v, new TimeZone.utc())); cfg.map("eat", o => o.expires_at != null ? ((!)o.expires_at).format_iso8601() : null, (o, v) => o.expires_at = v != null ? new DateTime.from_iso8601((!)v, new TimeZone.utc()) : null); cfg.set_constructor(() => new AuthorisationToken.blank()); }); } } }