示例#1
0
        public async Task <IActionResult> Create(LinkEditModel model)
        {
            if (ModelState.IsValid)
            {
                var verifyResult = _linkVerifier.Verify(model.OriginUrl, Url, Request);
                switch (verifyResult)
                {
                case LinkVerifyResult.InvalidFormat:
                    return(BadRequest("Not a valid URL."));

                case LinkVerifyResult.InvalidLocal:
                    return(BadRequest("Can not use local URL."));

                case LinkVerifyResult.InvalidSelfReference:
                    return(BadRequest("Can not use url pointing to this site."));
                }

                var createLinkRequest = new CreateLinkRequest
                {
                    OriginUrl = model.OriginUrl,
                    Note      = model.Note,
                    AkaName   = string.IsNullOrWhiteSpace(model.AkaName) ? null : model.AkaName,
                    IsEnabled = model.IsEnabled,
                    TTL       = model.TTL
                };

                var response = await _linkForwarderService.CreateLinkAsync(createLinkRequest);

                return(Json(response));
            }
            return(BadRequest("Invalid ModelState"));
        }
        private async Task<IActionResult> PerformTokenRedirection(string token, string ip, StringValues ua)
        {
            bool isValid = _tokenGenerator.TryParseToken(token, out var validatedToken);
            if (!isValid)
            {
                _logger.LogWarning($"'{ip}' requested invalid token '{token}'. Request is blocked.");
                return BadRequest();
            }

            if (!_cache.TryGetValue(token, out Link linkEntry))
            {
                var response = await _linkForwarderService.GetLinkAsync(validatedToken);
                if (response.IsSuccess)
                {
                    var link = response.Item;
                    if (null == link)
                    {
                        if (string.IsNullOrWhiteSpace(_appSettings.DefaultRedirectionUrl)) return NotFound();

                        var verifyDefaultRedirectionUrl =
                            _linkVerifier.Verify(_appSettings.DefaultRedirectionUrl, Url, Request);
                        if (verifyDefaultRedirectionUrl == LinkVerifyResult.Valid)
                        {
                            return Redirect(_appSettings.DefaultRedirectionUrl);
                        }

                        throw new UriFormatException("DefaultRedirectionUrl is not a valid URL.");
                    }

                    if (!link.IsEnabled)
                    {
                        return BadRequest("This link is disabled.");
                    }

                    var verifyOriginUrl = _linkVerifier.Verify(link.OriginUrl, Url, Request);
                    switch (verifyOriginUrl)
                    {
                        case LinkVerifyResult.Valid:
                            // cache valid link entity only.
                            if (null != link.TTL)
                            {
                                _cache.Set(token, link, TimeSpan.FromSeconds(link.TTL.GetValueOrDefault()));
                            }
                            break;
                        case LinkVerifyResult.InvalidFormat:
                            throw new UriFormatException(
                                $"OriginUrl '{link.OriginUrl}' is not a valid URL, link ID: {link.Id}.");
                        case LinkVerifyResult.InvalidLocal:
                            _logger.LogWarning($"Local redirection is blocked. link: {JsonSerializer.Serialize(link)}");
                            return BadRequest("Local redirection is blocked");
                        case LinkVerifyResult.InvalidSelfReference:
                            _logger.LogWarning(
                                $"Self reference redirection is blocked. link: {JsonSerializer.Serialize(link)}");
                            return BadRequest("Self reference redirection is blocked");
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
                else
                {
                    return new StatusCodeResult(StatusCodes.Status500InternalServerError);
                }
            }

            if (null == linkEntry)
            {
                linkEntry = _cache.Get<Link>(token);
            }

            if (_appSettings.HonorDNT)
            {
                // Check if browser sends "Do Not Track"
                var dntFlag = Request.Headers["DNT"];
                bool dnt = !string.IsNullOrWhiteSpace(dntFlag) && dntFlag == 1.ToString();

                if (!dnt)
                {
                    _ = Task.Run(async () =>
                    {
                        await _linkForwarderService.TrackSucessRedirectionAsync(
                            new LinkTrackingRequest(ip, ua, linkEntry.Id));
                    });
                }
            }

            return Redirect(linkEntry.OriginUrl);
        }
示例#3
0
        public async Task <IActionResult> Forward(string token)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(token))
                {
                    return(BadRequest());
                }

                var ip = HttpContext.Connection.RemoteIpAddress.ToString();
                var ua = Request.Headers["User-Agent"];
                if (string.IsNullOrWhiteSpace(ua))
                {
                    _logger.LogWarning($"'{ip}' requested token '{token}' without User Agent. Request is blocked.");
                    return(BadRequest());
                }

                bool isValid = _tokenGenerator.TryParseToken(token, out var validatedToken);
                if (!isValid)
                {
                    _logger.LogWarning($"'{ip}' requested invalid token '{token}'. Request is blocked.");
                    return(BadRequest());
                }

                if (!_cache.TryGetValue(token, out Link linkEntry))
                {
                    var response = await _linkForwarderService.GetLinkAsync(validatedToken);

                    if (response.IsSuccess)
                    {
                        var link = response.Item;
                        if (null == link)
                        {
                            if (string.IsNullOrWhiteSpace(_appSettings.DefaultRedirectionUrl))
                            {
                                return(NotFound());
                            }

                            var verifyDefaultRedirectionUrl = _linkVerifier.Verify(_appSettings.DefaultRedirectionUrl, Url, Request);
                            if (verifyDefaultRedirectionUrl == LinkVerifyResult.Valid)
                            {
                                return(Redirect(_appSettings.DefaultRedirectionUrl));
                            }

                            throw new UriFormatException("DefaultRedirectionUrl is not a valid URL.");
                        }

                        if (!link.IsEnabled)
                        {
                            return(BadRequest("This link is disabled."));
                        }

                        var verifyOriginUrl = _linkVerifier.Verify(link.OriginUrl, Url, Request);
                        switch (verifyOriginUrl)
                        {
                        case LinkVerifyResult.Valid:
                            // cache valid link entity only.
                            _cache.Set(token, link, TimeSpan.FromHours(1));
                            break;

                        case LinkVerifyResult.InvalidFormat:
                            throw new UriFormatException(
                                      $"OriginUrl '{link.OriginUrl}' is not a valid URL, link ID: {link.Id}.");

                        case LinkVerifyResult.InvalidLocal:
                            _logger.LogWarning($"Local redirection is blocked. link: {JsonConvert.SerializeObject(link)}");
                            return(BadRequest("Local redirection is blocked"));

                        case LinkVerifyResult.InvalidSelfReference:
                            _logger.LogWarning($"Self reference redirection is blocked. link: {JsonConvert.SerializeObject(link)}");
                            return(BadRequest("Self reference redirection is blocked"));

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                    else
                    {
                        return(new StatusCodeResult(StatusCodes.Status500InternalServerError));
                    }
                }

                if (null == linkEntry)
                {
                    linkEntry = _cache.Get <Link>(token);
                }

                _ = Task.Run(async() =>
                {
                    await _linkForwarderService.TrackSucessRedirectionAsync(ip, ua, linkEntry.Id);
                });

                return(Redirect(linkEntry.OriginUrl));
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                return(new StatusCodeResult(StatusCodes.Status500InternalServerError));
            }
        }
示例#4
0
        private async Task <IActionResult> PerformTokenRedirection(string token, string ip)
        {
            var isValid = _tokenGenerator.TryParseToken(token, out var validatedToken);

            if (!isValid)
            {
                return(BadRequest());
            }

            if (!_cache.TryGetValue(token, out Link linkEntry))
            {
                var flag = await _featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));

                var link = await _linkForwarderService.GetLinkAsync(validatedToken);

                if (link is null)
                {
                    if (string.IsNullOrWhiteSpace(_appSettings.DefaultRedirectionUrl))
                    {
                        return(NotFound());
                    }

                    var result = _linkVerifier.Verify(_appSettings.DefaultRedirectionUrl, Url, Request, flag);
                    if (result == LinkVerifyResult.Valid)
                    {
                        return(Redirect(_appSettings.DefaultRedirectionUrl));
                    }

                    throw new UriFormatException("DefaultRedirectionUrl is not a valid URL.");
                }

                if (!link.IsEnabled)
                {
                    return(BadRequest("This link is disabled."));
                }

                var verifyOriginUrl = _linkVerifier.Verify(link.OriginUrl, Url, Request, flag);
                switch (verifyOriginUrl)
                {
                case LinkVerifyResult.Valid:
                    // cache valid link entity only.
                    if (link.TTL is not null)
                    {
                        _cache.Set(token, link, TimeSpan.FromSeconds(link.TTL.GetValueOrDefault()));
                    }
                    break;

                case LinkVerifyResult.InvalidFormat:
                    throw new UriFormatException(
                              $"OriginUrl '{link.OriginUrl}' is not a valid URL, link ID: {link.Id}.");

                case LinkVerifyResult.InvalidLocal:
                    _logger.LogWarning($"Local redirection is blocked. link: {JsonSerializer.Serialize(link)}");
                    return(BadRequest("Local redirection is blocked"));

                case LinkVerifyResult.InvalidSelfReference:
                    _logger.LogWarning(
                        $"Self reference redirection is blocked. link: {JsonSerializer.Serialize(link)}");
                    return(BadRequest("Self reference redirection is blocked"));

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            linkEntry ??= _cache.Get <Link>(token);

            var honorDNTFlag = await _featureManager.IsEnabledAsync(nameof(FeatureFlags.HonorDNT));

            if (!honorDNTFlag)
            {
                return(Redirect(linkEntry.OriginUrl));
            }

            // Check if browser sends "Do Not Track"
            var dntFlag = Request.Headers["DNT"];
            var dnt     = !string.IsNullOrWhiteSpace(dntFlag) && dntFlag == "1";

            if (dnt)
            {
                return(Redirect(linkEntry.OriginUrl));
            }

            try
            {
                var req = new LinkTrackingRequest(ip, UserAgent, linkEntry.Id);
                await _linkForwarderService.TrackSucessRedirectionAsync(req);
            }
            catch (Exception e)
            {
                // Eat exception, pretend everything is fine
                // Do not block workflow here
                _logger.LogError(e.Message, e);
            }

            return(Redirect(linkEntry.OriginUrl));
        }