Ejemplo n.º 1
0
        /// return a new signed ticket string
        /// </summary>
        public static string MakeTicket(string eventName, DateTime startTime, double durationMinutes, string seat, Uri serverUrl, string key)
        {
            TimedTicket t = new TimedTicket();

            t.version         = CURRENT_VERSION;
            t.eventName       = eventName;
            t.startTime       = startTime.ToUniversalTime();
            t.durationMinutes = durationMinutes;
            t.seat            = seat;
            t.serverUrl       = serverUrl;
            t.Sign(key);
            return(t.ToString());
        }
        public bool PrecheckTicket(out string status)
        {
            if (String.IsNullOrEmpty(ticketString))
            {
                clientStatus = status = "No ticket";
                return(false);
            }
            TimedTicket t = new TimedTicket();

            try {
                t.Parse(ticketString);
            } catch (FormatException) {
                clientStatus = status = "Ticket badly formatted";
                return(false);
            }
            DateTime now = DateTime.UtcNow;

            if (!t.ClientCurrentAndValid(eventName, now))
            {
                if (t.eventName != eventName)
                {
                    clientStatus = status = "Ticket for wrong event";
                }
                else if (t.Finished(now))
                {
                    clientStatus = status = "Event has finished";
                }
                else if (t.MinutesUntilStart(now) > 0)
                {
                    clientStatus = status = "Event hasn't started yet";
                }
                else
                {
                    clientStatus = status = "Ticket not valid";
                }
                return(false);
            }
            clientStatus = status = "Ticket is ready to send";
            return(true);
        }
        void Start()
        {
            // generate default tickets?
            string key = getServerKey();

            if (defaultSeats > 0 && !String.IsNullOrEmpty(key))
            {
                try {
                    DateTime start = DateTime.ParseExact(defaultStartTime, TimedTicket.DATE_FORMAT, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime();
                    Debug.Log("Default tickets:");
                    string ticket = TimedTicket.MakeTicket(eventName, start, defaultDurationMinutes, WILDCARD_SEAT, null, key);
                    Debug.Log(ticket);
                    for (int i = 1; i <= defaultSeats; i++)
                    {
                        ticket = TimedTicket.MakeTicket(eventName, start, defaultDurationMinutes, Convert.ToString(i), null, key);
                        Debug.Log(ticket);
                    }
                } catch (FormatException e) {
                    logger.LogFormat(LogType.Error, $"start time format error {e}");
                }
            }
        }
        public void OnAuthResponseMessage(NetworkConnection conn, AuthResponseMessage msg)
        {
            if (msg.code == 100)
            {
                if (logger.LogEnabled())
                {
                    logger.LogFormat(LogType.Log, "Authentication Response: {0}", msg.message);
                }
                clientStatus = "Ticket accepted";
                // Invoke the event to complete a successful authentication
                OnClientAuthenticated.Invoke(conn);
            }
            else
            {
                logger.LogFormat(LogType.Error, "Authentication Response: {0}", msg.message);
                clientStatus = String.Format("Ticket rejected ({0})", msg.message);

                // Set this on the client for local reference
                conn.isAuthenticated = false;

                // disconnect the client
                conn.Disconnect();

                // debug/test...
                if (!String.IsNullOrEmpty(getServerKey()))
                {
                    TimedTicket t = new TimedTicket();
                    try {
                        t.Parse(ticketString);
                        t.Sign(getServerKey());
                        string ts = t.ToString();
                        logger.LogFormat(LogType.Error, "Self-sign ticket: {0}", ts);
                    } catch (FormatException e) {
                        logger.LogFormat(LogType.Error, "problem making self-sign ticket: {0}", e);
                    }
                }
            }
        }
        public void OnAuthRequestMessage(NetworkConnection conn, AuthRequestMessage msg)
        {
            if (logger.LogEnabled())
            {
                logger.LogFormat(LogType.Log, "Authentication Request: ticket {0}", msg.ticketString);
            }
            TimedTicket t = new TimedTicket();

            try {
                t.Parse(msg.ticketString);
            } catch (Exception e) {
                if (logger.LogEnabled())
                {
                    logger.LogFormat(LogType.Log, "Error parsing: ticket {0}: {1}", msg.ticketString, e);
                }
                sendError(conn, 200, "Could not parse ticket");
                return;
            }
            DateTime now = DateTime.UtcNow;

            // check the ticket
            if (t.ServerCurrentAndValid(eventName, now, getServerKey()))
            {
                // update for any recently disconnected cliens
                CheckCurrentSeatConnections();
                int numAuthenticated = NetworkServer.connections.Count(kv => kv.Value.isAuthenticated);

                SeatInfo si = null;
                if (t.seat != WILDCARD_SEAT)
                {
                    // if a non-wildcard user joins and they are not kicking
                    // someone then eject wildcard users in LIFO(?) order
                    // check/assign seat
                    if (!seats.ContainsKey(t.seat))
                    {
                        // new seat
                        si = new SeatInfo {
                            wildcard = false,
                            seat     = t.seat,
                            ticket   = t,
                            conn     = conn
                        };
                        seats.Add(t.seat, si);
                        if (logger.LogEnabled())
                        {
                            logger.LogFormat(LogType.Log, "Assigned new seat {0} to connection {1}", t.seat, conn.connectionId);
                        }
                        // kick wildcard users if necessary
                        if (numAuthenticated >= maxSeats)
                        {
                            if (!KickWildcardSeats(numAuthenticated + 1 - maxSeats))
                            {
                                // do we block numbered seats at the quota?!
                                // just note that people shouldn't send out
                                // more seats than set!
                            }
                        }
                    }
                    else
                    {
                        si = seats[t.seat];
                        if (si.conn != null)
                        {
                            if (t.durationMinutes > si.ticket.durationMinutes)
                            {
                                // current occupant has shorter duration => precedence
                                if (logger.LogEnabled())
                                {
                                    logger.LogFormat(LogType.Log, "Current seat {0} holder has precedence, {1} vs {2} minutes", si.seat, si.ticket.durationMinutes, t.durationMinutes);
                                }
                                sendError(conn, 200, "Seat is temporarily in use");
                                return;
                            }
                            if (logger.LogEnabled())
                            {
                                logger.LogFormat(LogType.Log, "Kick connection {0} from seat {1}, valid? {2}", si.conn.connectionId, si.seat, si.ticket.ServerCurrentAndValid(eventName, now, getServerKey()));
                            }
                            sendError(si.conn, 201, String.Format("Someone else has taken seat {0}", t.seat));
                        }
                        si.ticket = t;
                        si.conn   = conn;
                        if (logger.LogEnabled())
                        {
                            logger.LogFormat(LogType.Log, "Assigned existing seat {0} to connection {1}", t.seat, conn.connectionId);
                        }
                    }
                }
                else
                {
                    // would we need to kick a wildcard with longer duration?
                    if (numAuthenticated >= maxSeats || wildcardSeats.Count >= maxWildcardSeats)
                    {
                        // kick a wildcard with longer duration?!
                        if (wildcardSeats.Count > 0 && wildcardSeats[wildcardSeats.Count - 1].ticket.durationMinutes > t.durationMinutes)
                        {
                            if (KickWildcardSeats(1))
                            {
                                // that made a space!
                                numAuthenticated--;
                            }
                            else
                            {
                                if (logger.LogEnabled())
                                {
                                    logger.LogFormat(LogType.Error, "Unable to kick long duration wildcard");
                                }
                            }
                        }
                    }
                    // add a wildcard user if there is space.
                    if (numAuthenticated >= maxSeats || wildcardSeats.Count >= maxWildcardSeats)
                    {
                        if (logger.LogEnabled())
                        {
                            logger.LogFormat(LogType.Log, "No capacity for new wildcard seat, {0}/{1} and {2}/{3} total", wildcardSeats.Count, maxWildcardSeats, numAuthenticated, maxSeats);
                        }
                        sendError(conn, 200, "No space available");
                        return;
                    }
                    // new seat
                    si = new SeatInfo {
                        wildcard = true,
                        seat     = t.seat + (nextWildcardSeat++),
                        ticket   = t,
                        conn     = conn
                    };
                    // keep in increasing duration order, so longer tickets are kicked first
                    int shorter = wildcardSeats.Count(s => (s.ticket.durationMinutes <= t.durationMinutes));
                    wildcardSeats.Insert(shorter, si);
                    if (logger.LogEnabled())
                    {
                        logger.LogFormat(LogType.Log, "Assigned new seat {0} to connection {1}", si.seat, conn.connectionId);
                    }
                }
                // OK
                conn.authenticationData = t;

                // create and send msg to client so it knows to proceed
                AuthResponseMessage authResponseMessage = new AuthResponseMessage
                {
                    code    = 100,
                    message = "Success"
                };

                conn.Send(authResponseMessage);

                // check expire...
                if (si != null)
                {
                    StartCoroutine(MonitorTicketExpired(conn, si));
                }
                // Invoke the event to complete a successful authentication
                OnServerAuthenticated.Invoke(conn);
            }
            else
            {
                sendError(conn, 200, "Invalid Credentials");
            }
        }