예제 #1
0
        public void ShouldValidateDates()
        {
            var siweMessage = new SiweMessage();

            var startDate = DateTime.Now.ToUniversalTime().AddDays(1);

            siweMessage.SetNotBefore(startDate);
            Assert.False(siweMessage.HasMessageDateStarted());
            startDate = DateTime.Now.ToUniversalTime();
            siweMessage.SetNotBefore(startDate);
            Assert.True(siweMessage.HasMessageDateStarted());

            var expiryDate = DateTime.Now.ToUniversalTime().AddDays(1);

            siweMessage.SetExpirationTime(expiryDate);
            Assert.False(siweMessage.HasMessageDateExpired());

            expiryDate = DateTime.Now.ToUniversalTime();
            siweMessage.SetExpirationTime(expiryDate);
            Assert.True(siweMessage.HasMessageDateExpired());

            siweMessage.SetExpirationTime(DateTime.Now.ToUniversalTime().AddDays(1));
            siweMessage.SetNotBefore(DateTime.Now.ToUniversalTime().AddDays(-1));
            Assert.True(siweMessage.HasMessageDateStartedAndNotExpired());
        }
예제 #2
0
        public void ShouldValidateSignature()
        {
            var domain    = "login.xyz";
            var address   = "0xb8a316ea8a9e48ebd25b73c71bc0f22f5c337d1f";
            var statement = "Sign-In With Ethereum Example Statement";
            var uri       = "https://login.xyz";
            var version   = "1";
            var chainId   = "1";
            var nonce     = "uolthxpe";
            var issuedAt  = "2021-11-25T02:36:37.013Z";
            var signature = "0x6eabbdf0861ca83b6cf98381dcbc3db16dffce9a0449dc8b359718d13b0093c3285b6dea7e84ad1aa4871b63899319a988ddf39df3080bcdc60f68dd0942e8221c";
            var message   =
                "login.xyz wants you to sign in with your Ethereum account:\n0xb8a316ea8a9e48ebd25b73c71bc0f22f5c337d1f\n\nSign-In With Ethereum Example Statement\n\nURI: https://login.xyz\nVersion: 1\nChain ID: 1\nNonce: uolthxpe\nIssued At: 2021-11-25T02:36:37.013Z";
            var siweMessage = new SiweMessage();

            siweMessage.Domain    = domain;
            siweMessage.Address   = address;
            siweMessage.Statement = statement;
            siweMessage.Uri       = uri;
            siweMessage.Version   = version;
            siweMessage.ChainId   = chainId;
            siweMessage.Nonce     = nonce;
            siweMessage.IssuedAt  = issuedAt;
            siweMessage.Signature = signature;


            var builtMessage = SiweMessageStringBuilder.BuildMessage(siweMessage);

            Assert.Equal(message, builtMessage);
            var messageSigner    = new EthereumMessageSigner();
            var accountRecovered = messageSigner.EncodeUTF8AndEcRecover(builtMessage, signature);

            Assert.True(accountRecovered.IsTheSameAddress(address));
        }
예제 #3
0
        public void ShouldBuildANewMessageWithANewNonceAndValidateAfterSigning_UsingInMemoryNonceManagement()
        {
            var domain      = "login.xyz";
            var address     = "0x12890d2cce102216644c59daE5baed380d84830c";
            var statement   = "Sign-In With Ethereum Example Statement";
            var uri         = "https://login.xyz";
            var chainId     = "1";
            var siweMessage = new SiweMessage();

            siweMessage.Domain    = domain;
            siweMessage.Address   = address;
            siweMessage.Statement = statement;
            siweMessage.Uri       = uri;
            siweMessage.ChainId   = chainId;
            siweMessage.SetExpirationTime(DateTime.Now.ToUniversalTime().AddHours(1));
            var service       = new SiweMessageService(new InMemoryStorageSessionNonceManagement());
            var message       = service.BuildMessageToSign(siweMessage);
            var messageSigner = new EthereumMessageSigner();
            var signature     = messageSigner.EncodeUTF8AndSign(message,
                                                                new EthECKey("0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7"));

            siweMessage.Signature = signature;
            Assert.True(service.HasMessageDateStartedAndNotExpired(siweMessage));
            Assert.True(service.IsMessageSessionNonceValid(siweMessage));
            Assert.True(service.IsMessageSignatureValid(siweMessage));
            Assert.True(service.IsValidMessage(siweMessage));
        }
예제 #4
0
 private static string GetVersion(SiweMessage message)
 {
     if (string.IsNullOrEmpty(message.Version))
     {
         throw new ArgumentException("Version cannot be null or empty");
     }
     return(string.Format(VERSION, message.Version));
 }
예제 #5
0
 private static string GetDomain(SiweMessage message)
 {
     if (string.IsNullOrEmpty(message.Domain))
     {
         throw new ArgumentException("Domain cannot be null or empty");
     }
     return(string.Format(DOMAIN, message.Domain));
 }
예제 #6
0
 private static string GetChainId(SiweMessage message)
 {
     if (string.IsNullOrEmpty(message.ChainId))
     {
         throw new ArgumentException("ChainId cannot be null or empty");
     }
     return(string.Format(CHAIN_ID, message.ChainId));
 }
예제 #7
0
 private static string GetIssuedAt(SiweMessage message)
 {
     if (string.IsNullOrEmpty(message.IssuedAt))
     {
         throw new ArgumentException("IssuedAt cannot be null or empty");
     }
     return(string.Format(ISSUED_AT, message.IssuedAt));
 }
예제 #8
0
 public SiweMessage AssignNewNonce(SiweMessage siweMessage)
 {
     if (string.IsNullOrEmpty(siweMessage.Nonce))
     {
         siweMessage.Nonce = RandomNonceBuilder.GenerateNewNonce();
     }
     return(siweMessage);
 }
예제 #9
0
    private static string GetRequestId(SiweMessage message)
    {
        if (!string.IsNullOrEmpty(message.RequestId))
        {
            return(string.Format(REQUEST_ID, message.RequestId));
        }

        return(string.Empty);
    }
예제 #10
0
    private static string GetNotBefore(SiweMessage message)
    {
        if (!string.IsNullOrEmpty(message.NotBefore))
        {
            return(string.Format(NOT_BEFORE, message.NotBefore));
        }

        return(string.Empty);
    }
예제 #11
0
    private static string GetExpirationTime(SiweMessage message)
    {
        if (!string.IsNullOrEmpty(message.ExpirationTime))
        {
            return(string.Format(EXPIRATION_TIME, message.ExpirationTime));
        }

        return(string.Empty);
    }
예제 #12
0
    private static string GetStatement(SiweMessage message)
    {
        if (!string.IsNullOrEmpty(message.Statement))
        {
            return(string.Format(STATEMENT, message.Statement));
        }

        return(string.Empty);
    }
 public virtual void InvalidateSession(SiweMessage siweMessage)
 {
     if (_messages.ContainsKey(siweMessage.Nonce))
     {
         if (!_messages.TryRemove(siweMessage.Nonce, out SiweMessage siweMessageStored))
         {
             throw new Exception("Could not invalidate stored session, try again");
         }
     }
 }
예제 #14
0
    private static string GetAddress(SiweMessage message)
    {
        //should this be a checksum address?
        //if (message.Address.IsEthereumChecksumAddress())
        if (message.Address.IsValidEthereumAddressHexFormat())
        {
            return(string.Format(ADDRESS, message.Address));
        }

        throw new FormatException("Invalid address format");
    }
예제 #15
0
 private static string GetNonce(SiweMessage message)
 {
     if (string.IsNullOrEmpty(message.Nonce))
     {
         throw new ArgumentException("Nonce cannot be null or empty");
     }
     if (message.Nonce.Length < 8)
     {
         throw new ArgumentException("Nonce has to be bigger or equal to 8 characters");
     }
     return(string.Format(NONCE, message.Nonce));
 }
예제 #16
0
        public bool IsMessageSignatureValid(SiweMessage siweMessage)
        {
            var builtMessage     = SiweMessageStringBuilder.BuildMessage(siweMessage);
            var messageSigner    = new EthereumMessageSigner();
            var accountRecovered = messageSigner.EncodeUTF8AndEcRecover(builtMessage, siweMessage.Signature);

            if (accountRecovered.IsTheSameAddress(siweMessage.Address))
            {
                return(true);
            }
            return(false);
        }
    public virtual bool ValidateSiweMessageHasCorrectNonce(SiweMessage siweMessage)
    {
        if (_messages.ContainsKey(siweMessage.Nonce))
        {
            var currentMessage  = SiweMessageStringBuilder.BuildMessage(siweMessage);
            var existingMessage = SiweMessageStringBuilder.BuildMessage(_messages[siweMessage.Nonce]);
            if (currentMessage == existingMessage)
            {
                return(true);
            }
        }

        return(false);
    }
예제 #18
0
        public string BuildMessageToSign(SiweMessage siweMessage)
        {
            if (string.IsNullOrEmpty(siweMessage.IssuedAt))
            {
                siweMessage.SetIssuedAtNow();
            }

            if (string.IsNullOrEmpty(siweMessage.Version))
            {
                siweMessage.Version = "1";
            }

            _siweSessionNonceManagement.AssignNewNonce(siweMessage);
            return(SiweMessageStringBuilder.BuildMessage(siweMessage));
        }
    public virtual SiweMessage AssignNewNonce(SiweMessage siweMessage)
    {
        if (string.IsNullOrEmpty(siweMessage.Nonce))
        {
            siweMessage.Nonce = RandomNonceBuilder.GenerateNewNonce();
            _messages.AddOrUpdate(siweMessage.Nonce, siweMessage,
                                  (string nonce, SiweMessage oldSiweMessage) => siweMessage);
        }
        else
        {
            throw new Exception("Siwe message has a nonce already");
        }

        return(siweMessage);
    }
예제 #20
0
    private static string GetResources(SiweMessage message)
    {
        if (message.Resources != null && message.Resources.Count > 0)
        {
            var returnString = RESOURCES;
            foreach (var resource in message.Resources)
            {
                returnString += string.Format(RESOURCE, resource);
            }

            return(returnString);
        }

        return(string.Empty);
    }
예제 #21
0
 public static string BuildMessage(SiweMessage message)
 {
     return(GetDomain(message) +
            GetAddress(message) +
            GetStatement(message) +
            GetUriLine(message) +
            GetVersion(message) +
            GetChainId(message) +
            GetNonce(message) +
            GetIssuedAt(message) +
            GetExpirationTime(message) +
            GetNotBefore(message) +
            GetRequestId(message) +
            GetResources(message));
 }
예제 #22
0
 public void InvalidateSession(SiweMessage siweMessage)
 {
     throw new NotImplementedException();
 }
예제 #23
0
 public bool ValidateSiweMessageHasCorrectNonce(SiweMessage siweMessage)
 {
     return(!string.IsNullOrEmpty(siweMessage.Nonce));
 }
예제 #24
0
 public virtual bool IsValidMessage(SiweMessage siweMessage)
 {
     return(HasMessageDateStartedAndNotExpired(siweMessage) && IsMessageSignatureValid(siweMessage) &&
            IsMessageSessionNonceValid(siweMessage));
 }
예제 #25
0
 public bool IsMessageSessionNonceValid(SiweMessage siweMessage)
 {
     return(_siweSessionNonceManagement.ValidateSiweMessageHasCorrectNonce(siweMessage));
 }
예제 #26
0
 private static string GetUriLine(SiweMessage message)
 {
     return(string.Format(URI_LINE, message.Uri));
 }
예제 #27
0
 public virtual bool HasMessageDateStartedAndNotExpired(SiweMessage siweMessage)
 {
     return(siweMessage.HasMessageDateStartedAndNotExpired());
 }
예제 #28
0
 public MessageExtractor()
 {
     SiweMessage           = new SiweMessage();
     SiweMessage.Resources = new List <string>();
 }