/// 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"); } }