static void DecodeHar(string filePath) { string securityKey = "sVBa8Yy0xjAwXo+WQnmwcg=="; string sessionKey = "OQqKxKrYZ5cg1au2IN0WvA=="; using var file = new StreamReader(filePath); using var json = JsonDocument.Parse(file.ReadToEnd()); var ws = json.RootElement.GetProperty("log").GetProperty("entries").EnumerateArray().First(item => item.GetProperty("request").GetProperty("url").ToString() == "wss://link.xiatou.com/"); Message[] messages = JsonSerializer.Deserialize <Message[]>(ws.GetProperty("_webSocketMessages").ToString()); using var writer = new StreamWriter(@".\output.txt"); foreach (var message in messages) { if (message.type == "send") { #if DEBUG var us = Decode(typeof(UpstreamPayload), Convert.FromBase64String(message.data), securityKey, sessionKey, out var header) as UpstreamPayload; writer.WriteLine("Up\t\tHeaderSeqId {0}, SeqId {1}, Command: {2}", header.SeqId, us.SeqId, us.Command); writer.WriteLine("Header: {0}", header); writer.WriteLine("Payload: {0}", us); switch (us.Command) { case Command.REGISTER: var register = RegisterRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(register); break; case Command.KEEP_ALIVE: var keepalive = KeepAliveRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(keepalive); break; case Command.PING: var ping = PingRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(ping); break; case Command.MESSAGE_SESSION: var session = AcFunDanmu.Im.Message.Types.SessionListRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(session); break; case Command.MESSAGE_PULL_OLD: var pullold = AcFunDanmu.Im.Message.Types.PullOldRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(pullold); break; case Command.CLIENT_CONFIG_GET: var configget = AcFunDanmu.Im.Cloud.Types.Config.Types.ClientConfigGetRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(configget); break; case Command.GROUP_USER_GROUP_LIST: var usergrouplist = AcFunDanmu.Im.Cloud.Types.Message.Types.UserGroupListRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(usergrouplist); break; case Command.GLOBAL_COMMAND: ZtLiveCsCmd cmd = ZtLiveCsCmd.Parser.ParseFrom(us.PayloadData); writer.WriteLine("\t{0}: {1}", Command.GLOBAL_COMMAND, cmd); switch (cmd.CmdType) { case GlobalCommand.ENTER_ROOM: var enterRoom = ZtLiveCsEnterRoom.Parser.ParseFrom(cmd.Payload); writer.WriteLine("\t\t{0}", enterRoom); break; case GlobalCommand.HEARTBEAT: var heartbeat = ZtLiveCsHeartbeat.Parser.ParseFrom(cmd.Payload); writer.WriteLine("\t\t{0}", heartbeat); break; case GlobalCommand.USER_EXIT: var userExit = ZtLiveCsUserExit.Parser.ParseFrom(cmd.Payload); writer.WriteLine("\t\t{0}", userExit); break; default: Console.WriteLine("Unhandled Global.ZtLiveInteractive.CsCmd: {0}", cmd.CmdType); Console.WriteLine(cmd); break; } break; case Command.PUSH_MESSAGE: writer.WriteLine("\tUpstream Push.Message: {0}", us.PayloadData.ToBase64()); break; default: writer.WriteLine("Unknown upstream: {0}", us); break; } writer.WriteLine("--------------------------------"); #endif } else if (message.type == "receive") { var ds = Decode(typeof(DownstreamPayload), Convert.FromBase64String(message.data), securityKey, sessionKey, out var header) as DownstreamPayload; writer.WriteLine("Down\tHeaderSeqId {0}, SeqId {1}, Command: {2}", header.SeqId, ds.SeqId, ds.Command); writer.WriteLine("Header: {0}", header); writer.WriteLine("Payload: {0}", ds); switch (ds.Command) { case Command.REGISTER: var register = RegisterResponse.Parser.ParseFrom(ds.PayloadData); sessionKey = register.SessKey.ToBase64(); writer.WriteLine(register); break; case Command.KEEP_ALIVE: var keepalive = KeepAliveResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(keepalive); break; case Command.PING: var ping = PingResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(ping); break; case Command.MESSAGE_SESSION: var session = AcFunDanmu.Im.Message.Types.SessionListResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(session); break; case Command.MESSAGE_PULL_OLD: var pullold = AcFunDanmu.Im.Message.Types.PullOldResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(pullold); break; case Command.CLIENT_CONFIG_GET: var configget = AcFunDanmu.Im.Cloud.Types.Config.Types.ClientConfigGetResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(configget); break; case Command.GROUP_USER_GROUP_LIST: var usergrouplist = AcFunDanmu.Im.Cloud.Types.Message.Types.UserGroupListResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(usergrouplist); break; case Command.GLOBAL_COMMAND: ZtLiveCsCmdAck cmd = ZtLiveCsCmdAck.Parser.ParseFrom(ds.PayloadData); writer.WriteLine("\t{0}: {1}", Command.GLOBAL_COMMAND, cmd); switch (cmd.CmdAckType) { case GlobalCommand.ENTER_ROOM_ACK: var enterRoom = ZtLiveCsEnterRoomAck.Parser.ParseFrom(cmd.Payload); writer.WriteLine("\t\t{0}", enterRoom); break; case GlobalCommand.HEARTBEAT_ACK: var heartbeat = ZtLiveCsHeartbeatAck.Parser.ParseFrom(cmd.Payload); writer.WriteLine("\t\t{0}", heartbeat); break; case GlobalCommand.USER_EXIT_ACK: var userexit = ZtLiveCsUserExitAck.Parser.ParseFrom(cmd.Payload); writer.WriteLine("\t\t{0}", userexit); break; default: Console.WriteLine("Unhandled Global.ZtLiveInteractive.CsCmd: {0}", cmd.CmdAckType); Console.WriteLine(cmd); break; } break; case Command.PUSH_MESSAGE: ZtLiveScMessage scmessage = ZtLiveScMessage.Parser.ParseFrom(ds.PayloadData); writer.WriteLine("\t{0}: {1}", Command.PUSH_MESSAGE, scmessage); var payload = scmessage.CompressionType == ZtLiveScMessage.Types.CompressionType.Gzip ? Decompress(scmessage.Payload) : scmessage.Payload; switch (scmessage.MessageType) { case PushMessage.ACTION_SIGNAL: // Handled by user HandleSignal(scmessage.MessageType, payload.ToByteArray()); break; case PushMessage.STATE_SIGNAL: // Handled by user HandleSignal(scmessage.MessageType, payload.ToByteArray()); break; case PushMessage.STATUS_CHANGED: var statusChanged = ZtLiveScStatusChanged.Parser.ParseFrom(payload); writer.WriteLine("\t\t{0}", statusChanged); break; case PushMessage.TICKET_INVALID: var ticketInvalid = ZtLiveScTicketInvalid.Parser.ParseFrom(payload); writer.WriteLine("\t\t{0}", ticketInvalid); break; default: Console.WriteLine("Unhandled Push.ZtLiveInteractive.Message: {0}", scmessage.MessageType); break; } break; default: writer.WriteLine("Unkown downstream: {0}", ds); break; } writer.WriteLine("--------------------------------"); } } }
static void DecodeHar(string filePath) { var client = new Client( 1000000040695861, "ChRhY2Z1bi5hcGkudmlzaXRvci5zdBJwtK7G9ZWM4z4HKc4lbhpGECjvz6aOCfXQ36xgrn8wRFvS_L30QdkR2wQ9pRfxcj6GRn3Ymv2UwSrJpfzIDny8yDcqoDTdxFahdqhV58kJFnAUAQy8bZNgZksalDUyBi4Z9FTKRNKmxK5Xyz9typfPwhoS7u141z2YqvpCVbrK-LpEG0LFIiALNuXXoUE54trRZ9ZsQ-vcUwYRRvGOdTyZ4-mFNzz-bigFMAE", "emX88MTKZHee/PwU8yYLMw==", new string[] { "CgwxMC40NC4yMjIuMjMQkk4=", "CgwxMC40NC40MC4xODEQkk4=", "CgwxMC40NC4yMjIuMjMQk04=", "Cg0xMC41Mi4xODkuMTczEJNO" }, "nXc9rLOlKxcYhjIIURG6ZpXGOeCGewCG8aeVAQrHzMi7a/Pw9njsOuwH49nQwWf4HmSyLmC6yWz/cagN4tcSbg==", "y9Pi8EC4ulk", "JV3kqr1nefizjwACBCJ0DA==" ); using var file = new StreamReader(filePath); using var json = JsonDocument.Parse(file.ReadToEnd()); var ws = json.RootElement.GetProperty("log").GetProperty("entries").EnumerateArray().First(item => item.GetProperty("request").GetProperty("url").ToString() == "wss://link.xiatou.com/"); Message[] messages = JsonSerializer.Deserialize <Message[]>(ws.GetProperty("_webSocketMessages").ToString()); using var writer = new StreamWriter(@".\output.txt"); foreach (var message in messages) { if (message.type == "send") { var us = client.DecodeUpstream(Convert.FromBase64String(message.data)); writer.WriteLine("Up\tSeqId {0}, Command: {1}", us.SeqId, us.Command); //writer.Write("\t\t"); switch (us.Command) { case Command.REGISTER: var register = RegisterRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(register); break; case Command.KEEP_ALIVE: var keepalive = KeepAliveRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(keepalive); break; case Command.PING: var ping = PingRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(ping); break; case Command.MESSAGE_SESSION: var session = AcFunDanmu.Im.Message.Types.SessionListRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(session); break; case Command.MESSAGE_PULL_OLD: var pullold = AcFunDanmu.Im.Message.Types.PullOldRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(pullold); break; case Command.CLIENT_CONFIG_GET: var configget = AcFunDanmu.Im.Cloud.Types.Config.Types.ClientConfigGetRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(configget); break; case Command.GROUP_USER_GROUP_LIST: var usergrouplist = AcFunDanmu.Im.Cloud.Types.Message.Types.UserGroupListRequest.Parser.ParseFrom(us.PayloadData); writer.WriteLine(usergrouplist); break; case Command.GLOBAL_COMMAND: ZtLiveCsCmd cmd = ZtLiveCsCmd.Parser.ParseFrom(us.PayloadData); switch (cmd.CmdType) { case GlobalCommand.ENTER_ROOM: var enterRoom = ZtLiveCsEnterRoom.Parser.ParseFrom(cmd.Payload); break; case GlobalCommand.HEARTBEAT: var heartbeat = ZtLiveCsHeartbeat.Parser.ParseFrom(cmd.Payload); break; default: Console.WriteLine("Unhandled Global.ZtLiveInteractive.CsCmd: {0}", cmd.CmdType); Console.WriteLine(cmd); break; } break; case Command.PUSH_MESSAGE: Console.WriteLine(us.PayloadData.ToBase64()); break; default: writer.WriteLine(us); break; } writer.WriteLine("--------------------------------"); } else if (message.type == "receive") { var ds = client.Decode(Convert.FromBase64String(message.data)); writer.WriteLine("Down\tSeqId {0}, Command: {1}", ds.SeqId, ds.Command); //writer.Write("\t\t"); switch (ds.Command) { case Command.REGISTER: var register = RegisterResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(register); break; case Command.KEEP_ALIVE: var keepalive = KeepAliveResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(keepalive); break; case Command.PING: var ping = PingResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(ping); break; case Command.MESSAGE_SESSION: var session = AcFunDanmu.Im.Message.Types.SessionListResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(session); break; case Command.MESSAGE_PULL_OLD: var pullold = AcFunDanmu.Im.Message.Types.PullOldResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(pullold); break; case Command.CLIENT_CONFIG_GET: var configget = AcFunDanmu.Im.Cloud.Types.Config.Types.ClientConfigGetResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(configget); break; case Command.GROUP_USER_GROUP_LIST: var usergrouplist = AcFunDanmu.Im.Cloud.Types.Message.Types.UserGroupListResponse.Parser.ParseFrom(ds.PayloadData); writer.WriteLine(usergrouplist); break; case Command.GLOBAL_COMMAND: ZtLiveCsCmdAck cmd = ZtLiveCsCmdAck.Parser.ParseFrom(ds.PayloadData); switch (cmd.CmdAckType) { case GlobalCommand.ENTER_ROOM_ACK: var enterRoom = ZtLiveCsEnterRoomAck.Parser.ParseFrom(cmd.Payload); break; case GlobalCommand.HEARTBEAT_ACK: var heartbeat = ZtLiveCsHeartbeatAck.Parser.ParseFrom(cmd.Payload); break; default: Console.WriteLine("Unhandled Global.ZtLiveInteractive.CsCmd: {0}", cmd.CmdAckType); Console.WriteLine(cmd); break; } break; case Command.PUSH_MESSAGE: ZtLiveScMessage scmessage = ZtLiveScMessage.Parser.ParseFrom(ds.PayloadData); var payload = scmessage.CompressionType == ZtLiveScMessage.Types.CompressionType.Gzip ? Client.Decompress(scmessage.Payload) : scmessage.Payload; switch (scmessage.MessageType) { case PushMessage.ACTION_SIGNAL: // Handled by user HandleSignal(scmessage.MessageType, payload.ToByteArray()); break; case PushMessage.STATE_SIGNAL: // Handled by user HandleSignal(scmessage.MessageType, payload.ToByteArray()); break; case PushMessage.STATUS_CHANGED: var statusChanged = ZtLiveScStatusChanged.Parser.ParseFrom(payload); break; case PushMessage.TICKET_INVALID: var ticketInvalid = ZtLiveScTicketInvalid.Parser.ParseFrom(payload); break; default: Console.WriteLine("Unhandled Push.ZtLiveInteractive.Message: {0}", scmessage.MessageType); break; } break; default: writer.WriteLine(ds); break; } writer.WriteLine("--------------------------------"); } } }