public static string SignUrl(Action <TokenConfig> configFunc)
        {
            var config = new TokenConfig();

            configFunc(config);
            TokenConfigValidator.EnsureValid(config);

            var url           = AddCountrySettings(config, new Url(config.Url));
            var signaturePath = GetSignaturePath(config, url);

            var expires = config.ExpiresAt.ToUnixTimestamp();;

            var hashableBase = $"{config.SecurityKey}{signaturePath}{expires}{config.UserIp}{url.Query}";
            var token        = ReplaceChars(GetBase64EncodedHash(hashableBase));

            // Overwrite the token_path to urlencode it for the final url
            url.SetQueryParam("token_path", config.TokenPath);

            // Add expires
            url.SetQueryParam("expires", expires);

            if (config.IsDirectory)
            {
                return(url.Root + "/bcdn_token=" + token + "&" + url.Query + url.Path);
            }
            else
            {
                return(url.Root + url.Path + "?token=" + token + "&" + url.Query);
            }
        }
 private static string GetSignaturePath(TokenConfig config, Url url)
 {
     if (config.HasTokenPath)
     {
         url.SetQueryParam("token_path", config.TokenPath, true);
         return(config.TokenPath);
     }
     else
     {
         return(url.Path);
     }
 }
        private static Url AddCountrySettings(TokenConfig config, Url url)
        {
            if (config.CountriesAllowed.Any())
            {
                url.SetQueryParam("token_countries", string.Join(",", config.CountriesAllowed).ToUpperInvariant(), true);
            }

            if (config.CountriesBlocked.Any())
            {
                url.SetQueryParam("token_countries_blocked", string.Join(",", config.CountriesBlocked).ToUpperInvariant(), true);
            }

            return(url);
        }
        internal static void EnsureValid(TokenConfig config)
        {
            if (string.IsNullOrEmpty(config.SecurityKey))
            {
                throw new ArgumentNullException(nameof(config.SecurityKey), "Please set SecurityKey");
            }

            if (!config.HasExpiresAt)
            {
                throw new ArgumentNullException(nameof(config), "Please set ExpiresAt");
            }

            if (config.CountriesBlocked.Intersect(config.CountriesAllowed).Any())
            {
                throw new ArgumentException("There are country(s) in BOTH the allowed and blocked country lists.");
            }
        }