Click here to Skip to main content
15,886,059 members
Articles / Web Development / HTML

My own Mailinator in 5 minutes

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
19 Nov 2012CPOL6 min read 31.6K   405   13  
A simple Mailinator clone developed in five minutes with the NetFluid framework
using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.AUTH
{
    /// <summary>
    /// This class represents SASL DIGEST-MD5 authentication <b>digest-challenge</b>. Defined in RFC 2831.
    /// </summary>
    public class AUTH_SASL_DigestMD5_Challenge
    {
        private string[] m_Realm      = null;
        private string   m_Nonce      = null;
        private string[] m_QopOptions = null;
        private bool     m_Stale      = false;
        private int      m_Maxbuf     = 0;
        private string   m_Charset    = null;
        private string   m_Algorithm  = null;
        private string   m_CipherOpts = null;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="realm">Realm value.</param>
        /// <param name="nonce">Nonce value.</param>
        /// <param name="qopOptions">Quality of protections supported. Normally this is "auth".</param>
        /// <param name="stale">Stale value.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>realm</b>,<b>nonce</b> or <b>qopOptions</b> is null reference.</exception>
        public AUTH_SASL_DigestMD5_Challenge(string[] realm,string nonce,string[] qopOptions,bool stale)
        {
            if(realm == null){
                throw new ArgumentNullException("realm");
            }
            if(nonce == null){
                throw new ArgumentNullException("nonce");
            }
            if(qopOptions == null){
                throw new ArgumentNullException("qopOptions");
            }

            m_Realm      = realm;
            m_Nonce      = nonce;
            m_QopOptions = qopOptions;
            m_Stale      = stale;
            m_Charset    = "utf-8";
            m_Algorithm  = "md5-sess";
        }

        /// <summary>
        /// Internal parse constructor.
        /// </summary>
        private AUTH_SASL_DigestMD5_Challenge()
        {
        }


        #region static method Parse

        /// <summary>
        /// Parses DIGEST-MD5 challenge from challenge-string.
        /// </summary>
        /// <param name="challenge">Challenge string.</param>
        /// <returns>Returns DIGEST-MD5 challenge.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>challenge</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when challenge parsing + validation fails.</exception>
        public static AUTH_SASL_DigestMD5_Challenge Parse(string challenge)
        {
            if(challenge == null){
                throw new ArgumentNullException("challenge");
            }

            AUTH_SASL_DigestMD5_Challenge retVal = new AUTH_SASL_DigestMD5_Challenge();

            string[] parameters = TextUtils.SplitQuotedString(challenge,',');
            foreach(string parameter in parameters){
                string[] name_value = parameter.Split(new char[]{'='},2);
                string   name       = name_value[0].Trim();

                if(name_value.Length == 2){
                    if(name.ToLower() == "realm"){
                        retVal.m_Realm = TextUtils.UnQuoteString(name_value[1]).Split(',');
                    }
                    else if(name.ToLower() == "nonce"){
                        retVal.m_Nonce = TextUtils.UnQuoteString(name_value[1]);
                    }
                    else if(name.ToLower() == "qop"){
                        retVal.m_QopOptions = TextUtils.UnQuoteString(name_value[1]).Split(',');
                    }
                    else if(name.ToLower() == "stale"){
                        retVal.m_Stale = Convert.ToBoolean(TextUtils.UnQuoteString(name_value[1]));
                    }
                    else if(name.ToLower() == "maxbuf"){
                        retVal.m_Maxbuf = Convert.ToInt32(TextUtils.UnQuoteString(name_value[1]));
                    }
                    else if(name.ToLower() == "charset"){
                        retVal.m_Charset = TextUtils.UnQuoteString(name_value[1]);
                    }
                    else if(name.ToLower() == "algorithm"){
                        retVal.m_Algorithm = TextUtils.UnQuoteString(name_value[1]);
                    }
                    else if(name.ToLower() == "cipher-opts"){
                        retVal.m_CipherOpts = TextUtils.UnQuoteString(name_value[1]);
                    }
                    //else if(name.ToLower() == "auth-param"){
                    //    retVal.m_AuthParam = TextUtils.UnQuoteString(name_value[1]);
                    //}
                }
            }

            /* Validate required fields.
                Per RFC 2831 2.1.1. Only [nonce algorithm] parameters are required.
            */
            if(string.IsNullOrEmpty(retVal.Nonce)){
                throw new ParseException("The challenge-string doesn't contain required parameter 'nonce' value.");
            }
            if(string.IsNullOrEmpty(retVal.Algorithm)){
                throw new ParseException("The challenge-string doesn't contain required parameter 'algorithm' value.");
            }

            return retVal;
        }

        #endregion


        #region method ToChallenge

        /// <summary>
        /// Returns DIGEST-MD5 "digest-challenge" string.
        /// </summary>
        /// <returns>Returns DIGEST-MD5 "digest-challenge" string.</returns>
        public string ToChallenge()
        {
            /* RFC 2831 2.1.1.
                The server starts by sending a challenge. The data encoded in the
                challenge contains a string formatted according to the rules for a
                "digest-challenge" defined as follows:

                digest-challenge  =
                                    1#( realm | nonce | qop-options | stale | maxbuf | charset
                                        algorithm | cipher-opts | auth-param )

                realm             = "realm" "=" <"> realm-value <">
                realm-value       = qdstr-val
                nonce             = "nonce" "=" <"> nonce-value <">
                nonce-value       = qdstr-val
                qop-options       = "qop" "=" <"> qop-list <">
                qop-list          = 1#qop-value
                qop-value         = "auth" | "auth-int" | "auth-conf" | token
                stale             = "stale" "=" "true"
                maxbuf            = "maxbuf" "=" maxbuf-value
                maxbuf-value      = 1*DIGIT
                charset           = "charset" "=" "utf-8"
                algorithm         = "algorithm" "=" "md5-sess"
                cipher-opts       = "cipher" "=" <"> 1#cipher-value <">
                cipher-value      = "3des" | "des" | "rc4-40" | "rc4" | "rc4-56" | token
                auth-param        = token "=" ( token | quoted-string )
            */

            StringBuilder retVal = new StringBuilder();
            retVal.Append("realm=\"" + Net_Utils.ArrayToString(this.Realm,",") + "\"");
            retVal.Append(",nonce=\"" + this.Nonce + "\"");
            if(this.QopOptions != null){
                retVal.Append(",qop=\"" + Net_Utils.ArrayToString(this.QopOptions,",") + "\"");
            }
            if(this.Stale){
                retVal.Append(",stale=true");
            }
            if(this.Maxbuf > 0){
                retVal.Append(",maxbuf=" + this.Maxbuf);
            }
            if(!string.IsNullOrEmpty(this.Charset)){
                retVal.Append(",charset=" + this.Charset);
            }
            retVal.Append(",algorithm=" + this.Algorithm);
            if(!string.IsNullOrEmpty(this.CipherOpts)){
                retVal.Append(",cipher-opts=\"" + this.CipherOpts + "\"");
            }
            //if(!string.IsNullOrEmpty(this.AuthParam)){
            //    retVal.Append("auth-param=\"" + this.AuthParam + "\"");
            //}

            return retVal.ToString();
        }

        #endregion


        #region Properties implementation

        /// <summary>
        /// Gets realm value. For more info see RFC 2831.
        /// </summary>
        public string[] Realm
        {
            get{ return m_Realm; }
        }

        /// <summary>
        /// Gets nonce value. For more info see RFC 2831.
        /// </summary>
        public string Nonce
        {
            get{ return m_Nonce; }
        }

        /// <summary>
        /// Gets qop-options value. For more info see RFC 2831.
        /// </summary>
        public string[] QopOptions
        {
            get{ return m_QopOptions; }
        }

        /// <summary>
        /// Gets if stale value. For more info see RFC 2831.
        /// </summary>
        public bool Stale
        {
            get{ return m_Stale; }
        }

        /// <summary>
        /// Gets maxbuf value. For more info see RFC 2831.
        /// </summary>
        public int Maxbuf
        {
            get{ return m_Maxbuf; }
        }

        /// <summary>
        /// Gets charset value. For more info see RFC 2831.
        /// </summary>
        public string Charset
        {
            get{ return m_Charset; }
        }

        /// <summary>
        /// Gets algorithm value. For more info see RFC 2831.
        /// </summary>
        public string Algorithm
        {
            get{ return m_Algorithm; }
        }

        /// <summary>
        /// Gets cipher-opts value. For more info see RFC 2831.
        /// </summary>
        public string CipherOpts
        {
            get{ return m_CipherOpts; }
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Genny Mobility
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions