/// <summary> /// Initializes a new instance of the <see cref="GNTPWebSocketReader"/> class. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing a list of allowed passwords</param> /// <param name="passwordRequired">Indicates if a password is required</param> /// <param name="allowNetworkNotifications">Indicates if network requests are allowed</param> /// <param name="allowBrowserConnections">Indicates if browser requests are allowed</param> /// <param name="allowSubscriptions">Indicates if SUBSCRIPTION requests are allowed</param> /// <param name="requestInfo">The <see cref="RequestInfo"/> associated with this request</param> public GNTPWebSocketReader(AsyncSocket socket, PasswordManager passwordManager, bool passwordRequired, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions, RequestInfo requestInfo) : base(socket, passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, requestInfo) { this.allowed = allowBrowserConnections; parser = new GNTPParser2(passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, requestInfo); parser.MessageParsed += new GNTPParser2.GNTPParserMessageParsedEventHandler(parser_MessageParsed); parser.Error += new GNTPParser2.GNTPParserErrorEventHandler(parser_Error); }
/// <summary> /// Initializes a new instance of the <see cref="GNTPSocketReader"/> class. /// </summary> /// <param name="socket">The <see cref="AsyncSocket"/></param> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing a list of allowed passwords</param> /// <param name="passwordRequired">Indicates if a password is required</param> /// <param name="allowNetworkNotifications">Indicates if network requests are allowed</param> /// <param name="allowBrowserConnections">Indicates if browser requests are allowed</param> /// <param name="allowSubscriptions">Indicates if SUBSCRIPTION requests are allowed</param> /// <param name="requestInfo">The <see cref="RequestInfo"/> associated with this request</param> public GNTPSocketReader(AsyncSocket socket, PasswordManager passwordManager, bool passwordRequired, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions, RequestInfo requestInfo) { this.parser = new GNTPParser(passwordManager, passwordRequired, allowNetworkNotifications, allowBrowserConnections, allowSubscriptions, requestInfo); parser.Error += new GNTPParser.GNTPParserErrorEventHandler(parser_Error); parser.MessageParsed += new GNTPParser.GNTPParserMessageParsedEventHandler(parser_MessageParsed); this.socket = socket; this.socket.Tag = parser; }
/// <summary> /// Given the raw packet data, converts the data back into a <see cref="RegistrationPacket"/> /// </summary> /// <param name="bytes">The raw packet data</param> /// <param name="passwordManager">The list of client passwords</param> /// <param name="passwordRequired">Indicates if the request must supply a valid password</param> /// <returns><see cref="RegistrationPacket"/></returns> /// <remarks> /// If the client password does not match the password used to validate the sent notification, /// or if the packet is malformed in any way, a <c>null</c> object will be returned. /// </remarks> public static RegistrationPacket FromPacket(byte[] bytes, PasswordManager passwordManager, bool passwordRequired) { RegistrationPacket rp = null; // parse the packet if (bytes != null && bytes.Length > 18) { // check md5 hash first string password = null; bool valid = BasePacket.IsPasswordValid(bytes, passwordManager, passwordRequired, out password); if (!valid) return rp; int protocolVersion = (int)bytes[0]; PacketType packetType = (PacketType)bytes[1]; if (packetType == PacketType.Registration) { int index = 6; List<NotificationType> notificationTypes = new List<NotificationType>(); short applicationNameLength = BitConverter.ToInt16(new byte[] { bytes[3], bytes[2] }, 0); int notificationCount = (int)bytes[4]; int defaultNotificationCount = (int)bytes[5]; string applicationName = Encoding.UTF8.GetString(bytes, index, applicationNameLength); index += applicationNameLength; for (int n = 0; n < notificationCount; n++ ) { short notificationNameLength = BitConverter.ToInt16(new byte[] { bytes[index + 1], bytes[index] }, 0); string notificationName = Encoding.UTF8.GetString(bytes, index + 2, notificationNameLength); index += 2 + notificationNameLength; NotificationType nt = new NotificationType(notificationName, false); notificationTypes.Add(nt); } for (int d = 0; d < defaultNotificationCount; d++) { int notificationIndex = (int) bytes[index++]; notificationTypes[notificationIndex].Enabled = true; } rp = new RegistrationPacket(protocolVersion, applicationName, password, notificationTypes); } } return rp; }
private void button3_Click(object sender, EventArgs e) { if (this.isRunning) { this.server.Stop(); this.isRunning = false; this.button3.Text = "start server"; Write("server stopped"); //this.pollClient.Stop(); //this.pollServer.Stop(); } else { string historyFolder = System.Windows.Forms.Application.UserAppDataPath + @"\history"; Growl.Connector.PasswordManager pm = new Growl.Connector.PasswordManager(); //pm.Add(password); pm.Add(altPassword, true); this.server = new Growl.Daemon.GrowlServer(24000, pm, historyFolder); //this.server = new Growl.Daemon.GrowlServer(Growl.Connector.GrowlConnector.TCP_PORT, pm, historyFolder); this.server.RegisterReceived += new Growl.Daemon.GrowlServer.RegisterReceivedEventHandler(server_RegisterReceived); this.server.NotifyReceived += new Growl.Daemon.GrowlServer.NotifyReceivedEventHandler(server_NotifyReceived); this.server.SubscribeReceived += new Growl.Daemon.GrowlServer.SubscribeReceivedEventHandler(server_SubscribeReceived); this.server.ServerMessage += new Growl.Daemon.GrowlServer.ServerMessageEventHandler(server_ServerMessage); this.server.Start(); this.isRunning = true; this.button3.Text = "stop server"; this.textBox1.Text = ""; Write("server is listening"); //this.pollServer = new Growl.Polling.PollServer(7777, keyHex); //this.pollServer.Start(); //this.pollClient = new Growl.Polling.PollClient(keyHex, "*****@*****.**", "localhost", 7777, 10, "localhost", Growl.Connector.GrowlConnector.TCP_PORT); //this.pollClient.Start(); } }
/// <summary> /// Initializes a new instance of the <see cref="GNTPParser"/> class. /// </summary> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing a list of allowed passwords</param> /// <param name="passwordRequired">Indicates if a password is required</param> /// <param name="allowNetworkNotifications">Indicates if network requests are allowed</param> /// <param name="allowBrowserConnections">Indicates if browser requests are allowed</param> /// <param name="allowSubscriptions">Indicates if SUBSCRIPTION requests are allowed</param> /// <param name="requestInfo">The <see cref="RequestInfo"/> associated with this request</param> public GNTPParser2(PasswordManager passwordManager, bool passwordRequired, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions, RequestInfo requestInfo) { this.passwordManager = passwordManager; this.passwordRequired = passwordRequired; this.allowNetworkNotifications = allowNetworkNotifications; this.allowBrowserConnections = allowBrowserConnections; this.allowSubscriptions = allowSubscriptions; this.requestInfo = requestInfo; this.alreadyReceived = new StringBuilder(); this.headers = new HeaderCollection(); this.notificationsToBeRegistered = new List<HeaderCollection>(); this.pointers = new List<Pointer>(); this.callbackInfo = new CallbackInfo(); ms = new MemoryStream(); gntpReader = new GNTPStreamReader(ms); buffer = new List<byte>(); nextIndicator = AsyncSocket.CRLFData; tag = GNTP_IDENTIFIER_TAG; }
/// <summary> /// Creates a new instance of the Growl server. /// </summary> /// <param name="port">The port to listen on. The standard GNTP port is <see cref="ConnectorBase.TCP_PORT"/>.</param> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing the list of allowed passwords.</param> /// <param name="userFolder">The full path to the user folder where logs, resource cache, and other files will be stored.</param> public GrowlServer(int port, PasswordManager passwordManager, string userFolder) { // this will set the server name and version properly ServerName = serverName; this.port = (ushort) port; this.passwordManager = passwordManager; this.userFolder = userFolder; this.logFolder = PathUtility.Combine(userFolder, @"Log\"); PathUtility.EnsureDirectoryExists(this.logFolder); this.resourceFolder = PathUtility.Combine(userFolder, @"Resources\"); PathUtility.EnsureDirectoryExists(this.resourceFolder); this.listenSocket = new AsyncSocket(); this.listenSocket.AllowMultithreadedCallbacks = true; // VERY IMPORTANT: if we dont set this, async socket events will silently be swallowed by the AsyncSocket class listenSocket.DidAccept += new AsyncSocket.SocketDidAccept(listenSocket_DidAccept); //listenSocket.DidClose += new AsyncSocket.SocketDidClose(listenSocket_DidClose); // Initialize list to hold connected sockets // We support multiple concurrent connections connectedSockets = new ConnectedSocketCollection(); connectedHandlers = new Dictionary<AsyncSocket, MessageHandler>(); socketCleanupTimer = new System.Timers.Timer(30 * 1000); socketCleanupTimer.Elapsed += new System.Timers.ElapsedEventHandler(socketCleanupTimer_Elapsed); ResourceCache.ResourceFolder = this.resourceFolder; ResourceCache.Enabled = true; this.bonjour = new BonjourService(BonjourServiceName, BONJOUR_SERVICE_TYPE); }
/// <summary> /// Initializes a new instance of the <see cref="MessageHandler"/> class. /// </summary> /// <param name="serverName">Name of the server</param> /// <param name="passwordManager">A list of valid passwords</param> /// <param name="passwordRequired">Indicates if the request must contain a password</param> /// <param name="logFolder">The path to the folder where log files are written</param> /// <param name="loggingEnabled">Indicates if logging is enabled or not</param> /// <param name="allowNetworkNotifications">Indicates if notifications from remote machines are allowed</param> /// <param name="allowBrowserConnections">Indicates if notifications from browsers are allowed</param> /// <param name="allowSubscriptions">Indicates if clients are allowed to subscribe to notifications from this server</param> public MessageHandler(string serverName, PasswordManager passwordManager, bool passwordRequired, string logFolder, bool loggingEnabled, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions) { this.serverName = serverName; this.passwordManager = passwordManager; this.passwordRequired = passwordRequired; this.logFolder = logFolder; this.loggingEnabled = loggingEnabled; this.allowNetworkNotifications = allowNetworkNotifications; this.allowBrowserConnections = allowBrowserConnections; this.allowSubscriptions = allowSubscriptions; this.serverName = serverName; this.callbackInfo = new CallbackInfo(); this.requestInfo = new RequestInfo(); }
/// <summary> /// Initializes a new instance of the <see cref="GNTPParser"/> class. /// </summary> /// <param name="passwordManager">The <see cref="PasswordManager"/> containing a list of allowed passwords</param> /// <param name="passwordRequired">Indicates if a password is required</param> /// <param name="allowNetworkNotifications">Indicates if network requests are allowed</param> /// <param name="allowBrowserConnections">Indicates if browser requests are allowed</param> /// <param name="allowSubscriptions">Indicates if SUBSCRIPTION requests are allowed</param> /// <param name="requestInfo">The <see cref="RequestInfo"/> associated with this request</param> public GNTPParser(PasswordManager passwordManager, bool passwordRequired, bool allowNetworkNotifications, bool allowBrowserConnections, bool allowSubscriptions, RequestInfo requestInfo) { this.passwordManager = passwordManager; this.passwordRequired = passwordRequired; this.allowNetworkNotifications = allowNetworkNotifications; this.allowBrowserConnections = allowBrowserConnections; this.allowSubscriptions = allowSubscriptions; this.requestInfo = requestInfo; this.alreadyReceived = new StringBuilder(); this.headers = new HeaderCollection(); this.notificationsToBeRegistered = new List<HeaderCollection>(); this.pointers = new List<Pointer>(); this.callbackInfo = new CallbackInfo(); }
/// <summary> /// Checks to see if a given packets data matches a password /// provided by the receiving client and returns the matching password if found. /// </summary> /// <param name="bytes">The packets data</param> /// <param name="passwordManager">The receiving client's list of passwords</param> /// <param name="passwordRequired">Indicates if the request must supply a valid password</param> /// <param name="password">Returns the matching password if found; null otherwise</param> /// <returns><c>true</c> if the password matches, <c>false</c> otherwise</returns> protected static bool IsPasswordValid(byte[] bytes, PasswordManager passwordManager, bool passwordRequired, out string password) { password = null; byte[] packetWithoutPassword = new byte[bytes.Length - 16]; Array.Copy(bytes, 0, packetWithoutPassword, 0, packetWithoutPassword.Length); byte[] thatChecksum = new byte[16]; Array.Copy(bytes, bytes.Length - 16, thatChecksum, 0, 16); string thatChecksumString = Encoding.UTF8.GetString(thatChecksum); ByteBuilder bpb = new ByteBuilder(); bpb.Append(packetWithoutPassword); Queue<string> validPasswords = new Queue<string>(); foreach (KeyValuePair<string, Password> item in passwordManager.Passwords) { validPasswords.Enqueue(item.Key); } // if the request does not require a password, then // we can also try no (blank) password if (!passwordRequired) validPasswords.Enqueue(String.Empty); while(validPasswords.Count > 0) { string p = validPasswords.Dequeue(); ByteBuilder pb = new ByteBuilder(); pb.Append(bpb.GetBytes()); pb.Append(p); byte[] thisChecksum = Cryptography.ComputeHash(pb.GetBytes(), Cryptography.HashAlgorithmType.MD5); string thisChecksumString = Encoding.UTF8.GetString(thisChecksum); if (thisChecksumString == thatChecksumString) { password = p; return true; } } return false; }
/// <summary> /// Given the raw packet data, converts the data back into a <see cref="NotificationPacket"/> /// </summary> /// <param name="bytes">The raw packet data</param> /// <param name="passwordManager">The list of client passwords</param> /// <param name="passwordRequired">Indicates if the request must supply a valid password</param> /// <returns><see cref="NotificationPacket"/></returns> /// <remarks> /// If the client password does not match the password used to validate the sent notification, /// or if the packet is malformed in any way, a <c>null</c> object will be returned. /// </remarks> public static NotificationPacket FromPacket(byte[] bytes, PasswordManager passwordManager, bool passwordRequired) { NotificationPacket np = null; // parse the packet if (bytes != null && bytes.Length > 18) { // check md5 hash first string password = null; bool valid = BasePacket.IsPasswordValid(bytes, passwordManager, passwordRequired, out password); if (!valid) return np; int protocolVersion = (int)bytes[0]; PacketType packetType = (PacketType)bytes[1]; if (packetType == PacketType.Notification) { short flags = BitConverter.ToInt16(new byte[] { bytes[3], bytes[2] }, 0); bool sticky = ((flags & 1) == 1 ? true : false); Priority priority = ConvertFlagToPriority(flags); short notificationNameLength = BitConverter.ToInt16(new byte[] { bytes[5], bytes[4] }, 0); short titleLength = BitConverter.ToInt16(new byte[] { bytes[7], bytes[6] }, 0); short descriptionLength = BitConverter.ToInt16(new byte[] { bytes[9], bytes[8] }, 0); short applicationNameLength = BitConverter.ToInt16(new byte[] { bytes[11], bytes[10] }, 0); int index = 12; string notificationName = Encoding.UTF8.GetString(bytes, index, notificationNameLength); index += notificationNameLength; string title = Encoding.UTF8.GetString(bytes, index, titleLength); index += titleLength; string description = Encoding.UTF8.GetString(bytes, index, descriptionLength); index += descriptionLength; string applicationName = Encoding.UTF8.GetString(bytes, index, applicationNameLength); NotificationType nt = NotificationType.GetByName(notificationName); //TODO: np = new NotificationPacket(protocolVersion, applicationName, password, nt, title, description, priority, sticky); } } return np; }
/// <summary> /// Default constructor. /// </summary> public MessageReceiver(int port, PasswordManager passwordManager, bool loggingEnabled, string logFolder) { this.port = port; this.passwordManager = passwordManager; this.loggingEnabled = loggingEnabled; this.logFolder = logFolder; }