├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── .idea
├── .gitignore
├── IridiumNG.iml
├── modules.xml
└── vcs.xml
├── README-zh.md
├── README.md
├── config.json
├── frontend
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.png
│ ├── fonts
│ │ ├── OpenSans
│ │ │ ├── OpenSans-Bold.ttf
│ │ │ ├── OpenSans-BoldItalic.ttf
│ │ │ ├── OpenSans-ExtraBold.ttf
│ │ │ ├── OpenSans-ExtraBoldItalic.ttf
│ │ │ ├── OpenSans-Italic.ttf
│ │ │ ├── OpenSans-Light.ttf
│ │ │ ├── OpenSans-LightItalic.ttf
│ │ │ ├── OpenSans-Medium.ttf
│ │ │ ├── OpenSans-MediumItalic.ttf
│ │ │ ├── OpenSans-Regular.ttf
│ │ │ ├── OpenSans-SemiBold.ttf
│ │ │ └── OpenSans-SemiBoldItalic.ttf
│ │ ├── shicon.svg
│ │ ├── shicon.ttf
│ │ └── shicon.woff
│ ├── global.css
│ └── index.html
├── rollup.config.js
├── scripts
│ └── setupTypeScript.js
└── src
│ ├── App.svelte
│ ├── Packet.svelte
│ ├── main.js
│ ├── proto_raw_decoder.js
│ └── protobuf_decoder
│ ├── hexUtils.js
│ ├── protobufDecoder.js
│ ├── protobufPartDecoder.js
│ └── varintUtils.js
├── frontend_server.go
├── go.mod
├── go.sum
├── main.go
├── makefile
├── mt19937_64.go
├── proto_service.go
├── sniffer.go
└── util.go
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 |
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v3
18 | with:
19 | go-version: 1.18
20 | cache: true
21 |
22 | - name: Setup Node.js environment
23 | uses: actions/setup-node@v3.3.0
24 | with:
25 | node-version: 16.x
26 | cache: npm
27 | cache-dependency-path: ./frontend/package-lock.json
28 |
29 | - name: Build Frontend
30 | run: cd frontend && npm i && npm run build
31 |
32 | - name: Set up libpcap
33 | run: sudo apt-get install -y libpcap-dev
34 |
35 | - name: Build
36 | run: make pre-build && make build-win && make build-linux
37 |
38 | - name: Upload a Build Artifact
39 | uses: actions/upload-artifact@v3.1.0
40 | with:
41 | # Artifact name
42 | name: IridiumNG
43 | # A file, directory or wildcard pattern that describes what to upload
44 | path: ./build
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /vendor
3 |
4 | /data
5 |
6 | .DS_Store
7 |
8 | *.pcapng
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/IridiumNG.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # Iridium-NG
2 |
3 | A KCP packet sniffer + visualizer in one, backend rewritten in Go.
4 |
5 | 
6 |
7 | # 用法
8 |
9 | 你可以从Actions中下载到编译好的,或者自己从源码构建。
10 |
11 | 0. 往 `data/` 目录放入 `packetIds.json`, `Keys.json` 和 `proto/` 文件.
12 | 1. 确保你已安装 [Npcap driver](https://npcap.com/#download) 或 wireshark.
13 | 2. 使用命令 `-l` 列出电脑上所有网卡,编辑 `config.json` 设置网卡设备, 或者使用命令 `-ip 192.x.x.x` 自动通过ip寻找设备.
14 | 3. 打开 http://localhost:1984/,
15 |
16 | **注意:在进门之前开始抓包**
17 |
18 | # Config.json
19 |
20 | ```json
21 | {
22 | "deviceName" : "", // 网络设备名称, 例如 eth0
23 | "packetFilter" : [ // 这里列出的包名将不会在前端显示
24 | ""
25 | ],
26 | "autoSavePcapFiles" : true // 自动保存抓包记录文件
27 | }
28 | ```
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Iridium-NG
2 |
3 | A KCP packet sniffer + visualizer in one, backend rewritten in Go.
4 |
5 | 
6 |
7 | [中文说明](/README-zh.md)
8 |
9 | # Usage
10 |
11 | You can download the binary(win/linux) from Actions, or build from source
12 |
13 | 0. Bring your `packetIds.json`, `Keys.json` and `proto/` to the `data/` folder.
14 | 1. Make sure you have installed [Npcap driver](https://npcap.com/#download) or wireshark.
15 | 2. Use cmd `-l` to list the network devices on your computer and edit `config.json` to set the device by its name, or use cmd `-ip 192.x.x.x` to let it auto find the device by its ip.
16 | 3. Open http://localhost:1984/
17 |
18 | **Notice: START CAPTURE BEFORE YOU ENTER THE DOOR**
19 |
20 | # Config.json
21 |
22 | ```json
23 | {
24 | "deviceName" : "", // network device name, such as eth0
25 | "packetFilter" : [ // the packets listed here will not show in frontend
26 | ""
27 | ],
28 | "autoSavePcapFiles" : true // auto save capture to current folder
29 | }
30 | ```
31 |
32 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "deviceName" : "",
3 | "packetFilter" : [
4 | ""
5 | ],
6 | "autoSavePcapFiles" : true
7 | }
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /public/build/
3 |
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | *Psst — looking for a more complete solution? Check out [SvelteKit](https://kit.svelte.dev), the official framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.*
2 |
3 | *Looking for a shareable component template instead? You can [use SvelteKit for that as well](https://kit.svelte.dev/docs#packaging) or the older [sveltejs/component-template](https://github.com/sveltejs/component-template)*
4 |
5 | ---
6 |
7 | # svelte app
8 |
9 | This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
10 |
11 | To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
12 |
13 | ```bash
14 | npx degit sveltejs/template svelte-app
15 | cd svelte-app
16 | ```
17 |
18 | *Note that you will need to have [Node.js](https://nodejs.org) installed.*
19 |
20 |
21 | ## Get started
22 |
23 | Install the dependencies...
24 |
25 | ```bash
26 | cd svelte-app
27 | npm install
28 | ```
29 |
30 | ...then start [Rollup](https://rollupjs.org):
31 |
32 | ```bash
33 | npm run dev
34 | ```
35 |
36 | Navigate to [localhost:8080](http://localhost:8080). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
37 |
38 | By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
39 |
40 | If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense.
41 |
42 | ## Building and running in production mode
43 |
44 | To create an optimised version of the app:
45 |
46 | ```bash
47 | npm run build
48 | ```
49 |
50 | You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).
51 |
52 |
53 | ## Single-page app mode
54 |
55 | By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.
56 |
57 | If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json:
58 |
59 | ```js
60 | "start": "sirv public --single"
61 | ```
62 |
63 | ## Using TypeScript
64 |
65 | This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with:
66 |
67 | ```bash
68 | node scripts/setupTypeScript.js
69 | ```
70 |
71 | Or remove the script via:
72 |
73 | ```bash
74 | rm scripts/setupTypeScript.js
75 | ```
76 |
77 | If you want to use `baseUrl` or `path` aliases within your `tsconfig`, you need to set up `@rollup/plugin-alias` to tell Rollup to resolve the aliases. For more info, see [this StackOverflow question](https://stackoverflow.com/questions/63427935/setup-tsconfig-path-in-svelte).
78 |
79 | ## Deploying to the web
80 |
81 | ### With [Vercel](https://vercel.com)
82 |
83 | Install `vercel` if you haven't already:
84 |
85 | ```bash
86 | npm install -g vercel
87 | ```
88 |
89 | Then, from within your project folder:
90 |
91 | ```bash
92 | cd public
93 | vercel deploy --name my-project
94 | ```
95 |
96 | ### With [surge](https://surge.sh/)
97 |
98 | Install `surge` if you haven't already:
99 |
100 | ```bash
101 | npm install -g surge
102 | ```
103 |
104 | Then, from within your project folder:
105 |
106 | ```bash
107 | npm run build
108 | surge public my-project.surge.sh
109 | ```
110 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-app",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "rollup -c",
7 | "dev": "rollup -c -w",
8 | "start": "sirv public --no-clear"
9 | },
10 | "devDependencies": {
11 | "@rollup/plugin-commonjs": "^17.1.0",
12 | "@rollup/plugin-node-resolve": "^11.2.1",
13 | "rollup": "^2.75.6",
14 | "rollup-plugin-css-only": "^3.1.0",
15 | "rollup-plugin-livereload": "^2.0.5",
16 | "rollup-plugin-svelte": "^7.1.0",
17 | "rollup-plugin-terser": "^7.0.2",
18 | "svelte": "^3.49.0",
19 | "svelte-highlight": "^5.3.2"
20 | },
21 | "dependencies": {
22 | "buffer": "^6.0.3",
23 | "jsbi": "^4.3.0",
24 | "sirv-cli": "^2.0.2",
25 | "svelte-jsoneditor": "^0.3.60",
26 | "svelte-virtual-list-ce": "^3.1.0-beta.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/favicon.png
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-Bold.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-BoldItalic.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-ExtraBold.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-Italic.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-Light.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-LightItalic.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-Medium.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-MediumItalic.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-Regular.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-SemiBold.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/OpenSans/OpenSans-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/OpenSans/OpenSans-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/shicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/frontend/public/fonts/shicon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/shicon.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/shicon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Akka0/Iridium-NG/43cde009836a1fd1ae3e9ca000edd38ec2b74133/frontend/public/fonts/shicon.woff
--------------------------------------------------------------------------------
/frontend/public/global.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;700&display=swap');
2 |
3 | /* http://meyerweb.com/eric/tools/css/reset/
4 | v2.0-modified | 20110126
5 | License: none (public domain)
6 | */
7 |
8 | html, body, div, span, applet, object, iframe,
9 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
10 | a, abbr, acronym, address, big, cite, code,
11 | del, dfn, em, img, ins, kbd, q, s, samp,
12 | small, strike, strong, sub, sup, tt, var,
13 | b, u, i, center,
14 | dl, dt, dd, ol, ul, li,
15 | fieldset, form, label, legend,
16 | table, caption, tbody, tfoot, thead, tr, th, td,
17 | article, aside, canvas, details, embed,
18 | figure, figcaption, footer, header, hgroup,
19 | menu, nav, output, ruby, section, summary,
20 | time, mark, audio, video {
21 | margin: 0;
22 | padding: 0;
23 | border: 0;
24 | font-size: 100%;
25 | font: inherit;
26 | vertical-align: baseline;
27 | }
28 |
29 | /* make sure to set some focus styles for accessibility */
30 | :focus {
31 | outline: 0;
32 | }
33 |
34 | /* HTML5 display-role reset for older browsers */
35 | article, aside, details, figcaption, figure,
36 | footer, header, hgroup, menu, nav, section {
37 | display: block;
38 | }
39 |
40 | body {
41 | line-height: 1;
42 | }
43 |
44 | ol, ul {
45 | list-style: none;
46 | }
47 |
48 | blockquote, q {
49 | quotes: none;
50 | }
51 |
52 | blockquote:before, blockquote:after,
53 | q:before, q:after {
54 | content: '';
55 | content: none;
56 | }
57 |
58 | table {
59 | border-collapse: collapse;
60 | border-spacing: 0;
61 | }
62 |
63 | input[type=search]::-webkit-search-cancel-button,
64 | input[type=search]::-webkit-search-decoration,
65 | input[type=search]::-webkit-search-results-button,
66 | input[type=search]::-webkit-search-results-decoration {
67 | -webkit-appearance: none;
68 | -moz-appearance: none;
69 | }
70 |
71 | input[type=search] {
72 | -webkit-appearance: none;
73 | -moz-appearance: none;
74 | -webkit-box-sizing: content-box;
75 | -moz-box-sizing: content-box;
76 | box-sizing: content-box;
77 | }
78 |
79 | textarea {
80 | overflow: auto;
81 | vertical-align: top;
82 | resize: vertical;
83 | }
84 |
85 | /**
86 | * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
87 | */
88 |
89 | audio,
90 | canvas,
91 | video {
92 | display: inline-block;
93 | *display: inline;
94 | *zoom: 1;
95 | max-width: 100%;
96 | }
97 |
98 | /**
99 | * Prevent modern browsers from displaying `audio` without controls.
100 | * Remove excess height in iOS 5 devices.
101 | */
102 |
103 | audio:not([controls]) {
104 | display: none;
105 | height: 0;
106 | }
107 |
108 | /**
109 | * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.
110 | * Known issue: no IE 6 support.
111 | */
112 |
113 | [hidden] {
114 | display: none;
115 | }
116 |
117 | /**
118 | * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using
119 | * `em` units.
120 | * 2. Prevent iOS text size adjust after orientation change, without disabling
121 | * user zoom.
122 | */
123 |
124 | html {
125 | font-size: 100%;/* 1 */
126 | -webkit-text-size-adjust: 100%;/* 2 */
127 | -ms-text-size-adjust: 100%; /* 2 */
128 | }
129 |
130 | /**
131 | * Address `outline` inconsistency between Chrome and other browsers.
132 | */
133 |
134 | a:focus {
135 | outline: thin dotted;
136 | }
137 |
138 | /**
139 | * Improve readability when focused and also mouse hovered in all browsers.
140 | */
141 |
142 | a:active,
143 | a:hover {
144 | outline: 0;
145 | }
146 |
147 | /**
148 | * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.
149 | * 2. Improve image quality when scaled in IE 7.
150 | */
151 |
152 | img {
153 | border: 0; /* 1 */
154 | -ms-interpolation-mode: bicubic; /* 2 */
155 | }
156 |
157 | /**
158 | * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
159 | */
160 |
161 | figure {
162 | margin: 0;
163 | }
164 |
165 | /**
166 | * Correct margin displayed oddly in IE 6/7.
167 | */
168 |
169 | form {
170 | margin: 0;
171 | }
172 |
173 | /**
174 | * Define consistent border, margin, and padding.
175 | */
176 |
177 | fieldset {
178 | border: 1px solid #c0c0c0;
179 | margin: 0 2px;
180 | padding: 0.35em 0.625em 0.75em;
181 | }
182 |
183 | /**
184 | * 1. Correct color not being inherited in IE 6/7/8/9.
185 | * 2. Correct text not wrapping in Firefox 3.
186 | * 3. Correct alignment displayed oddly in IE 6/7.
187 | */
188 |
189 | legend {
190 | border: 0; /* 1 */
191 | padding: 0;
192 | white-space: normal; /* 2 */
193 | *margin-left: -7px; /* 3 */
194 | }
195 |
196 | /**
197 | * 1. Correct font size not being inherited in all browsers.
198 | * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,
199 | * and Chrome.
200 | * 3. Improve appearance and consistency in all browsers.
201 | */
202 |
203 | button,
204 | input,
205 | select,
206 | textarea {
207 | font-size: 100%; /* 1 */
208 | margin: 0; /* 2 */
209 | vertical-align: baseline; /* 3 */
210 | *vertical-align: middle; /* 3 */
211 | }
212 |
213 | /**
214 | * Address Firefox 3+ setting `line-height` on `input` using `!important` in
215 | * the UA stylesheet.
216 | */
217 |
218 | button,
219 | input {
220 | line-height: normal;
221 | }
222 |
223 | /**
224 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
225 | * All other form control elements do not inherit `text-transform` values.
226 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.
227 | * Correct `select` style inheritance in Firefox 4+ and Opera.
228 | */
229 |
230 | button,
231 | select {
232 | text-transform: none;
233 | }
234 |
235 | /**
236 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
237 | * and `video` controls.
238 | * 2. Correct inability to style clickable `input` types in iOS.
239 | * 3. Improve usability and consistency of cursor style between image-type
240 | * `input` and others.
241 | * 4. Remove inner spacing in IE 7 without affecting normal text inputs.
242 | * Known issue: inner spacing remains in IE 6.
243 | */
244 |
245 | button,
246 | html input[type="button"], /* 1 */
247 | input[type="reset"],
248 | input[type="submit"] {
249 | -webkit-appearance: button; /* 2 */
250 | cursor: pointer; /* 3 */
251 | *overflow: visible; /* 4 */
252 | }
253 |
254 | /**
255 | * Re-set default cursor for disabled elements.
256 | */
257 |
258 | button[disabled],
259 | html input[disabled] {
260 | cursor: default;
261 | }
262 |
263 | /**
264 | * 1. Address box sizing set to content-box in IE 8/9.
265 | * 2. Remove excess padding in IE 8/9.
266 | * 3. Remove excess padding in IE 7.
267 | * Known issue: excess padding remains in IE 6.
268 | */
269 |
270 | input[type="checkbox"],
271 | input[type="radio"] {
272 | box-sizing: border-box; /* 1 */
273 | padding: 0; /* 2 */
274 | *height: 13px; /* 3 */
275 | *width: 13px; /* 3 */
276 | }
277 |
278 | /**
279 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
280 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
281 | * (include `-moz` to future-proof).
282 | */
283 |
284 | input[type="search"] {
285 | -webkit-appearance: textfield; /* 1 */
286 | -moz-box-sizing: content-box;
287 | -webkit-box-sizing: content-box; /* 2 */
288 | box-sizing: content-box;
289 | }
290 |
291 | /**
292 | * Remove inner padding and search cancel button in Safari 5 and Chrome
293 | * on OS X.
294 | */
295 |
296 | input[type="search"]::-webkit-search-cancel-button,
297 | input[type="search"]::-webkit-search-decoration {
298 | -webkit-appearance: none;
299 | }
300 |
301 | /**
302 | * Remove inner padding and border in Firefox 3+.
303 | */
304 |
305 | button::-moz-focus-inner,
306 | input::-moz-focus-inner {
307 | border: 0;
308 | padding: 0;
309 | }
310 |
311 | /**
312 | * 1. Remove default vertical scrollbar in IE 6/7/8/9.
313 | * 2. Improve readability and alignment in all browsers.
314 | */
315 |
316 | textarea {
317 | overflow: auto; /* 1 */
318 | vertical-align: top; /* 2 */
319 | }
320 |
321 | /**
322 | * Remove most spacing between table cells.
323 | */
324 |
325 | table {
326 | border-collapse: collapse;
327 | border-spacing: 0;
328 | }
329 |
330 | html,
331 | button,
332 | input,
333 | select,
334 | textarea {
335 | color: #222;
336 | }
337 |
338 |
339 | ::-moz-selection {
340 | background: #b3d4fc;
341 | text-shadow: none;
342 | }
343 |
344 | ::selection {
345 | background: #b3d4fc;
346 | text-shadow: none;
347 | }
348 |
349 | img {
350 | vertical-align: middle;
351 | }
352 |
353 | fieldset {
354 | border: 0;
355 | margin: 0;
356 | padding: 0;
357 | }
358 |
359 | textarea {
360 | resize: vertical;
361 | }
362 |
363 | .chromeframe {
364 | margin: 0.2em 0;
365 | background: #ccc;
366 | color: #000;
367 | padding: 0.2em 0;
368 | }
369 |
370 |
371 | @font-face {
372 | font-family: 'shicon';
373 | src:
374 | url('fonts/shicon.ttf?kckii0') format('truetype'),
375 | url('fonts/shicon.woff?kckii0') format('woff'),
376 | url('fonts/shicon.svg?kckii0#shicon') format('svg');
377 | font-weight: normal;
378 | font-style: normal;
379 | font-display: block;
380 | }
381 |
382 | [data-icon]:before {
383 | /* use !important to prevent issues with browser extensions that change fonts */
384 | font-family: 'shicon' !important;
385 | speak: never;
386 | font-style: normal;
387 | font-weight: normal;
388 | font-variant: normal;
389 | text-transform: none;
390 | line-height: 1;
391 |
392 | /* Better Font Rendering =========== */
393 | -webkit-font-smoothing: antialiased;
394 | -moz-osx-font-smoothing: grayscale;
395 | }
396 |
397 | [data-icon="network-off-outline"]:before{content:"\e924"}
398 | [data-icon="play-network-outline"]:before{content:"\e934"}
399 | [data-icon="open-in-app"]:before{content:"\e937"}
400 | [data-icon="card-off"]:before{content:"\e923"}
401 | [data-icon="sharios"]:before{content:"\e922"}
402 | [data-icon="image-off-1"]:before{content:"\e921"}
403 | [data-icon="language"]:before{content:"\e918"}
404 | [data-icon="twitter"]:before{content:"\e916"}
405 | [data-icon="discord"]:before{content:"\e917"}
406 | [data-icon="heart"]:before{content:"\e912"}
407 | [data-icon="help"]:before{content:"\e910"}
408 | [data-icon="numeric-3"]:before{content:"\e90e"}
409 | [data-icon="numeric-4"]:before{content:"\e90f"}
410 | [data-icon="arrow-all"]:before{content:"\e90a"}
411 | [data-icon="email-outline"]:before{content:"\e90b"}
412 | [data-icon="keyboard_arrow_down"]:before{content:"\e90c"}
413 | [data-icon="information-outline"]:before{content:"\e90d"}
414 | [data-icon="clear"]:before{content:"\e911"}
415 | [data-icon="keyboard_arrow_left"]:before{content:"\e913"}
416 | [data-icon="keyboard_arrow_right"]:before{content:"\e914"}
417 | [data-icon="keyboard_arrow_up"]:before{content:"\e915"}
418 | [data-icon="fullscreen"]:before{content:"\e91a"}
419 | [data-icon="unfold_more"]:before{content:"\e91b"}
420 | [data-icon="check_box"]:before{content:"\e91c"}
421 | [data-icon="check_box_outline_blank"]:before{content:"\e91d"}
422 | [data-icon="collections_bookmark"]:before{content:"\e925"}
423 | [data-icon="code"]:before{content:"\e926"}
424 | [data-icon="chat"]:before{content:"\e927"}
425 | [data-icon="link"]:before{content:"\e928"}
426 | [data-icon="launch"]:before{content:"\e929"}
427 | [data-icon="file"]:before{content:"\e92a"}
428 | [data-icon="crop_free"]:before{content:"\e92b"}
429 | [data-icon="crop_original"]:before{content:"\e92c"}
430 | [data-icon="zoom_out_map"]:before{content:"\e92d"}
431 | [data-icon="fullscreen_exit"]:before{content:"\e92e"}
432 | [data-icon="menu"]:before{content:"\e92f"}
433 | [data-icon="keyboard_control"]:before{content:"\e930"}
434 | [data-icon="more_vert"]:before{content:"\e931"}
435 | [data-icon="search"]:before{content:"\e932"}
436 | [data-icon="settings"]:before{content:"\e933"}
437 | [data-icon="insert_drive_file"]:before{content:"\e935"}
438 | [data-icon="file-image-outline"]:before{content:"\e936"}
439 | [data-icon="pan"]:before{content:"\e939"}
440 | [data-icon="image"]:before{content:"\e93b"}
441 | [data-icon="zoom-out"]:before{content:"\e93c"}
442 | [data-icon="zoom-in"]:before{content:"\e93d"}
443 | [data-icon="cogs"]:before{content:"\e93e"}
444 | [data-icon="view-grid-plus"]:before{content:"\e93f"}
445 | [data-icon="palette"]:before{content:"\e941"}
446 | [data-icon="download"]:before{content:"\e942"}
447 | [data-icon="check"]:before{content:"\e943"}
448 | [data-icon="home"]:before{content:"\e944"}
449 | [data-icon="loading"]:before{content:"\e97c"}
450 | [data-icon="layout-gid"]:before{content:"\e91f"}
451 | [data-icon="layout-wide"]:before{content:"\e919"}
452 | [data-icon="layout-mid"]:before{content:"\e91e"}
453 | [data-icon="shinshin"]:before{content:"\e920"}
454 | [data-icon="art0"]:before{content:"\e900"}
455 | [data-icon="art1"]:before{content:"\e901"}
456 | [data-icon="art2"]:before{content:"\e902"}
457 | [data-icon="art3"]:before{content:"\e903"}
458 | [data-icon="art4"]:before{content:"\e904"}
459 | [data-icon="weapon"]:before{content:"\e905"}
460 | [data-icon="const"]:before{content:"\e906"}
461 | [data-icon="table"]:before{content:"\e907"}
462 | [data-icon="talent"]:before{content:"\e908"}
463 | [data-icon="info"]:before{content:"\e909"}
464 |
465 |
466 | body {
467 | font-family: 'Open Sans', sans-serif;
468 | background: #333;
469 | display: flex;
470 | min-height: 100vh;
471 | max-height: 100vh;
472 | max-width: 100vw;
473 | align-items: stretch;
474 | justify-content: stretch;
475 | color: white;
476 | }
477 |
478 | button {
479 | background: #4360A2;
480 | border: 0;
481 | border-bottom: 2px solid rgba(0,0,0,0.4);
482 | padding: 0.3em 0.4em;
483 | color: inherit;
484 |
485 | }
486 |
487 | button:hover {
488 | filter: brightness(1.5)
489 | }
490 |
491 | .green {
492 | background: green;
493 | }
494 | .red {
495 | background: darkred;
496 | }
497 |
498 |
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Iridium frontend
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/frontend/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import commonjs from '@rollup/plugin-commonjs';
3 | import resolve from '@rollup/plugin-node-resolve';
4 | import livereload from 'rollup-plugin-livereload';
5 | import { terser } from 'rollup-plugin-terser';
6 | import css from 'rollup-plugin-css-only';
7 |
8 | const production = !process.env.ROLLUP_WATCH;
9 |
10 | function serve() {
11 | let server;
12 |
13 | function toExit() {
14 | if (server) server.kill(0);
15 | }
16 |
17 | return {
18 | writeBundle() {
19 | if (server) return;
20 | server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
21 | stdio: ['ignore', 'inherit', 'inherit'],
22 | shell: true
23 | });
24 |
25 | process.on('SIGTERM', toExit);
26 | process.on('exit', toExit);
27 | }
28 | };
29 | }
30 |
31 | export default {
32 | input: 'src/main.js',
33 | output: {
34 | sourcemap: true,
35 | format: 'iife',
36 | name: 'app',
37 | file: 'public/build/bundle.js',
38 | inlineDynamicImports: true,
39 | },
40 | plugins: [
41 | svelte({
42 | compilerOptions: {
43 | // enable run-time checks when not in production
44 | dev: !production
45 | }
46 | }),
47 | // we'll extract any component CSS out into
48 | // a separate file - better for performance
49 | css({ output: 'bundle.css' }),
50 |
51 | // If you have external dependencies installed from
52 | // npm, you'll most likely need these plugins. In
53 | // some cases you'll need additional configuration -
54 | // consult the documentation for details:
55 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
56 | resolve({
57 | browser: true,
58 | dedupe: ['svelte']
59 | }),
60 | commonjs(),
61 |
62 | // In dev mode, call `npm run start` once
63 | // the bundle has been generated
64 | !production && serve(),
65 |
66 | // Watch the `public` directory and refresh the
67 | // browser on changes when not in production
68 | !production && livereload('public'),
69 |
70 | // If we're building for production (npm run build
71 | // instead of npm run dev), minify
72 | production && terser()
73 | ],
74 | watch: {
75 | clearScreen: false
76 | }
77 | };
78 |
--------------------------------------------------------------------------------
/frontend/scripts/setupTypeScript.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | /** This script modifies the project to support TS code in .svelte files like:
4 |
5 |
8 |
9 | As well as validating the code for CI.
10 | */
11 |
12 | /** To work on this script:
13 | rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
14 | */
15 |
16 | const fs = require("fs")
17 | const path = require("path")
18 | const { argv } = require("process")
19 |
20 | const projectRoot = argv[2] || path.join(__dirname, "..")
21 |
22 | // Add deps to pkg.json
23 | const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"))
24 | packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
25 | "svelte-check": "^2.0.0",
26 | "svelte-preprocess": "^4.0.0",
27 | "@rollup/plugin-typescript": "^8.0.0",
28 | "typescript": "^4.0.0",
29 | "tslib": "^2.0.0",
30 | "@tsconfig/svelte": "^2.0.0"
31 | })
32 |
33 | // Add script for checking
34 | packageJSON.scripts = Object.assign(packageJSON.scripts, {
35 | "check": "svelte-check --tsconfig ./tsconfig.json"
36 | })
37 |
38 | // Write the package JSON
39 | fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " "))
40 |
41 | // mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
42 | const beforeMainJSPath = path.join(projectRoot, "src", "main.js")
43 | const afterMainTSPath = path.join(projectRoot, "src", "main.ts")
44 | fs.renameSync(beforeMainJSPath, afterMainTSPath)
45 |
46 | // Switch the app.svelte file to use TS
47 | const appSveltePath = path.join(projectRoot, "src", "App.svelte")
48 | let appFile = fs.readFileSync(appSveltePath, "utf8")
49 | appFile = appFile.replace("
270 |
271 |
272 | {@html materialDarker}
273 |
274 |
275 |
339 |
340 |
341 |
349 |
350 |
351 |
352 |
Time
353 |
#
354 |
Sender
355 |
ID
356 |
Proto Name
357 |
Length
358 |
JSON
359 |
360 |
361 |
367 | {
372 | showPacketDetails(packet);
373 | scrollToIndex(Math.max(currentPacket.index - 5, 0));
374 | }}
375 | />
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
Time
384 |
#
385 |
Sender
386 |
ID
387 |
Proto Name
388 |
Length
389 |
JSON
390 |
391 |
392 |
398 |
399 | showPacketDetails(packet)}
404 | />
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 | {#if currentPacket}
413 | {#if currentPacket.object}
414 |
415 |
420 |
421 | {/if}
422 | {#if currentPacket.decode && showDecode}
423 |
424 |
425 |
426 | {/if}
427 | {/if}
428 |
429 |
430 |
431 |
641 |
--------------------------------------------------------------------------------
/frontend/src/Packet.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | {#if packet.reltime}{packet.reltime.toFixed(3)}{/if}
14 |
15 |
{idx}
16 |
17 | {packet.source ? "CLIENT" : "SERVER"}
20 |
21 |
{packet.packetID}
22 |
{packet.protoName}
23 |
{packetLength || ""}
24 |
{packetString}
25 |
26 |
27 |
84 |
--------------------------------------------------------------------------------
/frontend/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte';
2 |
3 | const app = new App({
4 | target: document.body,
5 | props: {
6 | name: 'world'
7 | }
8 | });
9 |
10 | export default app;
--------------------------------------------------------------------------------
/frontend/src/proto_raw_decoder.js:
--------------------------------------------------------------------------------
1 | const { decodeProto, TYPES } = require("./protobuf_decoder/protobufDecoder");
2 | const {
3 | decodeFixed32,
4 | decodeFixed64,
5 | decodeVarintParts,
6 | } = require("./protobuf_decoder/protobufPartDecoder");
7 | const { parseInput } = require("./protobuf_decoder/hexUtils");
8 | const {
9 | decodeVarint,
10 | interpretAsSignedType,
11 | } = require("./protobuf_decoder/varintUtils");
12 |
13 | function parseType(decodeList) {
14 | return decodeList.reduce((pre, cur, index, arr) => {
15 | if (index === 0) {
16 | return `${cur.type}:${cur.value}`;
17 | } else {
18 | }
19 | return `${pre}, ${cur.type}:${cur.value}`;
20 | }, "");
21 | }
22 |
23 | function getNextIndex(key, repeatedMap) {
24 | if (!repeatedMap[key]) {
25 | repeatedMap[key] = 0;
26 | }
27 | repeatedMap[key]++;
28 | return repeatedMap[key] < 2 ? key : `${key}#${repeatedMap[key].toString()}`;
29 | }
30 |
31 | function processProtoPart(raw) {
32 | const data = decodeProto(parseInput(raw));
33 | const result = {};
34 | const repeatedMap = {};
35 | data.parts.forEach((e) => {
36 | let key;
37 | let res;
38 | switch (e.type) {
39 | case TYPES.FIXED32:
40 | const fixed32 = decodeFixed32(e.value);
41 | key = getNextIndex(`${e.index}:32b`, repeatedMap);
42 | res = parseType(fixed32);
43 | break;
44 |
45 | case TYPES.FIXED64:
46 | const fixed64 = decodeFixed64(e.value);
47 | key = getNextIndex(`${e.index}:64b`, repeatedMap);
48 | res = parseType(fixed64);
49 | break;
50 |
51 | case TYPES.VARINT:
52 | const varint = decodeVarintParts(e.value);
53 | key = getNextIndex(`${e.index}:varint`, repeatedMap);
54 | res = parseType(varint);
55 | break;
56 |
57 | case TYPES.STRING:
58 | const str = processProtoPart(e.value.toString("base64"));
59 | key = getNextIndex(`${e.index}:ld`, repeatedMap);
60 |
61 | if (e.value.length > 0 && !str.leftOver) {
62 | res = str;
63 | } else {
64 | res = [];
65 | decodeRepeated(e, res);
66 |
67 | res.push(
68 | `String:${e.value.toString()}, Raw:${e.value.toString("hex")}`
69 | );
70 | }
71 |
72 | break;
73 | }
74 | result[key] = res;
75 | });
76 |
77 | if (data.leftOver && data.leftOver.length > 0) {
78 | result.leftOver = data.leftOver.toString("base64");
79 | }
80 |
81 | return result;
82 | }
83 |
84 | function decodeRepeated(e, res) {
85 | try {
86 | let list = [];
87 | let len = 0;
88 | while (len < e.value.length) {
89 | const reslove = decodeVarint(e.value, len);
90 | len += reslove.length;
91 | list.push(reslove.value);
92 | }
93 |
94 | if (list.length > 0) {
95 | res.push(`Repeated Int:[${list.toString()}]`);
96 |
97 | if (list[0] !== interpretAsSignedType(list[0])) {
98 | const newList = list.map((i) => interpretAsSignedType(i));
99 | res.push(`Repeated Signed Int:[${newList.toString()}]`);
100 | }
101 | }
102 | } catch (ex) {
103 | // it must be not this type
104 | }
105 | }
106 |
107 | function protoRawDecode(raw) {
108 | return processProtoPart(raw);
109 | }
110 |
111 | module.exports = {
112 | protoRawDecode,
113 | };
114 |
--------------------------------------------------------------------------------
/frontend/src/protobuf_decoder/hexUtils.js:
--------------------------------------------------------------------------------
1 | /*
2 | Source: https://github.com/pawitp/protobuf-decoder by pawitp
3 | Modified to adapt common-js
4 | */
5 | const Buffer = require('buffer/').Buffer
6 |
7 | function parseInput(input) {
8 | const normalizedInput = input.replace(/\s/g, "");
9 | const normalizedHexInput = normalizedInput.replace(/0x/g, "").toLowerCase();
10 | if (isHex(normalizedHexInput)) {
11 | return Buffer.from(normalizedHexInput, "hex");
12 | } else {
13 | return Buffer.from(normalizedInput, "base64");
14 | }
15 | }
16 |
17 | function isHex(string) {
18 | let result = true;
19 | for (const char of string) {
20 | if (!((char >= "a" && char <= "f") || (char >= "0" && char <= "9"))) {
21 | result = false;
22 | }
23 | }
24 | return result;
25 | }
26 |
27 | function bufferToPrettyHex(buffer) {
28 | let output = "";
29 | for (const v of buffer) {
30 | if (output !== "") {
31 | output += " ";
32 | }
33 |
34 | const hex = v.toString(16);
35 | if (hex.length === 1) {
36 | output += "0" + hex;
37 | } else {
38 | output += hex;
39 | }
40 | }
41 | return output;
42 | }
43 |
44 | function bufferLeToBeHex(buffer) {
45 | let output = "";
46 | for (const v of buffer) {
47 | const hex = v.toString(16);
48 | if (hex.length === 1) {
49 | output = "0" + hex + output;
50 | } else {
51 | output = hex + output;
52 | }
53 | }
54 | return output;
55 | }
56 |
57 | module.exports = {
58 | parseInput, isHex, bufferToPrettyHex, bufferLeToBeHex
59 | }
--------------------------------------------------------------------------------
/frontend/src/protobuf_decoder/protobufDecoder.js:
--------------------------------------------------------------------------------
1 | /*
2 | Source: https://github.com/pawitp/protobuf-decoder by pawitp
3 | Modified to adapt common-js
4 | */
5 | const { decodeVarint } = require("./varintUtils");
6 |
7 | class BufferReader {
8 | constructor(buffer) {
9 | this.buffer = buffer;
10 | this.offset = 0;
11 | }
12 |
13 | readVarInt() {
14 | const result = decodeVarint(this.buffer, this.offset);
15 | this.offset += result.length;
16 |
17 | return result.value;
18 | }
19 |
20 | readBuffer(length) {
21 | this.checkByte(length);
22 | const result = this.buffer.slice(this.offset, this.offset + length);
23 | this.offset += length;
24 |
25 | return result;
26 | }
27 |
28 | // gRPC has some additional header - remove it
29 | trySkipGrpcHeader() {
30 | const backupOffset = this.offset;
31 |
32 | if (this.buffer[this.offset] === 0) {
33 | this.offset++;
34 | const length = this.buffer.readInt32BE(this.offset);
35 | this.offset += 4;
36 |
37 | if (length > this.leftBytes()) {
38 | // Something is wrong, revert
39 | this.offset = backupOffset;
40 | }
41 | }
42 | }
43 |
44 | leftBytes() {
45 | return this.buffer.length - this.offset;
46 | }
47 |
48 | checkByte(length) {
49 | const bytesAvailable = this.leftBytes();
50 | if (length > bytesAvailable) {
51 | throw new Error(
52 | "Not enough bytes left. Requested: " +
53 | length +
54 | " left: " +
55 | bytesAvailable
56 | );
57 | }
58 | }
59 |
60 | checkpoint() {
61 | this.savedOffset = this.offset;
62 | }
63 |
64 | resetToCheckpoint() {
65 | this.offset = this.savedOffset;
66 | }
67 | }
68 |
69 | const TYPES = {
70 | VARINT: 0,
71 | FIXED64: 1,
72 | STRING: 2,
73 | FIXED32: 5
74 | };
75 |
76 | function decodeProto(buffer) {
77 | const reader = new BufferReader(buffer);
78 | const parts = [];
79 |
80 | reader.trySkipGrpcHeader();
81 |
82 | try {
83 | while (reader.leftBytes() > 0) {
84 | reader.checkpoint();
85 |
86 | const indexType = parseInt(reader.readVarInt().toString());
87 | const type = indexType & 0b111;
88 | const index = indexType >> 3;
89 |
90 | let value;
91 | if (type === TYPES.VARINT) {
92 | value = reader.readVarInt().toString();
93 | } else if (type === TYPES.STRING) {
94 | const length = parseInt(reader.readVarInt().toString());
95 | value = reader.readBuffer(length);
96 | } else if (type === TYPES.FIXED32) {
97 | value = reader.readBuffer(4);
98 | } else if (type === TYPES.FIXED64) {
99 | value = reader.readBuffer(8);
100 | } else {
101 | throw new Error("Unknown type: " + type);
102 | }
103 |
104 | parts.push({
105 | index,
106 | type,
107 | value
108 | });
109 | }
110 | } catch (err) {
111 | reader.resetToCheckpoint();
112 | }
113 |
114 | return {
115 | parts,
116 | leftOver: reader.readBuffer(reader.leftBytes())
117 | };
118 | }
119 |
120 | function typeToString(type) {
121 | switch (type) {
122 | case TYPES.VARINT:
123 | return "varint";
124 | case TYPES.STRING:
125 | return "string";
126 | case TYPES.FIXED32:
127 | return "fixed32";
128 | case TYPES.FIXED64:
129 | return "fixed64";
130 | default:
131 | return "unknown";
132 | }
133 | }
134 |
135 | module.exports = {
136 | TYPES, decodeProto, typeToString
137 | }
--------------------------------------------------------------------------------
/frontend/src/protobuf_decoder/protobufPartDecoder.js:
--------------------------------------------------------------------------------
1 | /*
2 | Source: https://github.com/pawitp/protobuf-decoder by pawitp
3 | Modified to adapt common-js
4 | */
5 | const JSBI = require("jsbi");
6 | const { bufferLeToBeHex } = require( "./hexUtils");
7 | const { interpretAsSignedType } = require( "./varintUtils");
8 |
9 | function decodeFixed32(value) {
10 | const floatValue = value.readFloatLE(0);
11 | const intValue = value.readInt32LE(0);
12 | const uintValue = value.readUInt32LE(0);
13 |
14 | const result = [];
15 |
16 | result.push({ type: "Int", value: intValue });
17 |
18 | if (intValue !== uintValue) {
19 | result.push({ type: "Unsigned Int", value: uintValue });
20 | }
21 |
22 | result.push({ type: "Float", value: floatValue });
23 |
24 | return result;
25 | }
26 |
27 | function decodeFixed64(value) {
28 | const floatValue = value.readDoubleLE(0);
29 | const uintValue = JSBI.BigInt("0x" + bufferLeToBeHex(value));
30 | const intValue = twoComplements(uintValue);
31 |
32 | const result = [];
33 |
34 | result.push({ type: "Int", value: intValue.toString() });
35 |
36 | if (intValue !== uintValue) {
37 | result.push({ type: "Unsigned Int", value: uintValue.toString() });
38 | }
39 |
40 | result.push({ type: "Double", value: floatValue });
41 |
42 | return result;
43 | }
44 |
45 | function decodeVarintParts(value) {
46 | const result = [];
47 | const intVal = JSBI.BigInt(value);
48 | result.push({ type: "Int", value: intVal.toString() });
49 |
50 | const signedIntVal = interpretAsSignedType(intVal);
51 | if (signedIntVal !== intVal) {
52 | result.push({ type: "Signed Int", value: signedIntVal.toString() });
53 | }
54 | return result;
55 | }
56 |
57 | const maxLong = JSBI.BigInt("0x7fffffffffffffff");
58 | const longForComplement = JSBI.BigInt("0x10000000000000000");
59 |
60 | function twoComplements(uintValue) {
61 | if (JSBI.greaterThan(uintValue, maxLong)) {
62 | return JSBI.subtract(uintValue, longForComplement);
63 | } else {
64 | return uintValue;
65 | }
66 | }
67 |
68 | module.exports = {
69 | decodeFixed32, decodeFixed64, decodeVarintParts
70 | }
--------------------------------------------------------------------------------
/frontend/src/protobuf_decoder/varintUtils.js:
--------------------------------------------------------------------------------
1 | /*
2 | Source: https://github.com/pawitp/protobuf-decoder by pawitp
3 | Modified to adapt common-js
4 | */
5 | const JSBI = require("jsbi");
6 |
7 | const BIGINT_1 = JSBI.BigInt(1);
8 | const BIGINT_2 = JSBI.BigInt(2);
9 |
10 | function interpretAsSignedType(n) {
11 | // see https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/wire_format_lite.h#L857-L876
12 | // however, this is a simpler equivalent formula
13 | const isEven = JSBI.equal(JSBI.bitwiseAnd(n, JSBI.BigInt(1)), JSBI.BigInt(0));
14 | if (isEven) {
15 | return JSBI.divide(n, BIGINT_2);
16 | } else {
17 | return JSBI.multiply(
18 | JSBI.BigInt(-1),
19 | JSBI.divide(JSBI.add(n, BIGINT_1), BIGINT_2)
20 | );
21 | }
22 | }
23 |
24 | function decodeVarint(buffer, offset) {
25 | let res = JSBI.BigInt(0);
26 | let shift = 0;
27 | let byte = 0;
28 |
29 | do {
30 | if (offset >= buffer.length) {
31 | throw new RangeError("Index out of bound decoding varint");
32 | }
33 |
34 | byte = buffer[offset++];
35 |
36 | const multiplier = JSBI.exponentiate(BIGINT_2, JSBI.BigInt(shift));
37 | const thisByteValue = JSBI.multiply(JSBI.BigInt(byte & 0x7f), multiplier);
38 | shift += 7;
39 | res = JSBI.add(res, thisByteValue);
40 | } while (byte >= 0x80);
41 |
42 | return {
43 | value: res,
44 | length: shift / 7
45 | };
46 | }
47 |
48 | module.exports = {
49 | interpretAsSignedType, decodeVarint
50 | }
51 |
--------------------------------------------------------------------------------
/frontend_server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "embed"
5 | "github.com/gin-gonic/contrib/static"
6 | "github.com/gin-gonic/gin"
7 | "io"
8 | "io/fs"
9 | "log"
10 | "net/http"
11 | "os"
12 | )
13 |
14 | var eventStream = make(chan string)
15 |
16 | //go:embed frontend/public
17 | var staticFolder embed.FS
18 |
19 | func startServer() {
20 | r := gin.Default()
21 | r.GET("/api/start", apiStart)
22 | r.GET("/api/stop", apiStop)
23 | r.POST("/api/upload", apiUpload)
24 | r.GET("/api/stream", stream)
25 | r.Use(static.Serve("/", EmbedFolder(staticFolder, "frontend/public")))
26 |
27 | defer close(eventStream)
28 | err := r.Run(":1984")
29 | if err != nil {
30 | log.Fatalln("Could not start http server", err)
31 | }
32 | }
33 |
34 | func apiStart(c *gin.Context) {
35 | go openCapture()
36 | }
37 |
38 | func apiStop(c *gin.Context) {
39 | go closeHandle()
40 | }
41 |
42 | func apiUpload(c *gin.Context) {
43 | file, err := c.FormFile("file")
44 | if err != nil {
45 | log.Println("Could not handle upload file", err)
46 | return
47 | }
48 | err = c.SaveUploadedFile(file, os.TempDir()+file.Filename)
49 | if err != nil {
50 | log.Println("Could not handle upload file", err)
51 | return
52 | }
53 | go openPcap(os.TempDir() + file.Filename)
54 | }
55 |
56 | func stream(c *gin.Context) {
57 | c.Stream(func(w io.Writer) bool {
58 | c.SSEvent("packetNotify", <-eventStream)
59 | return true
60 | })
61 | }
62 |
63 | func sendStreamMsg(msg string) {
64 | go func() {
65 | eventStream <- msg
66 | }()
67 | }
68 |
69 | type embedFileSystem struct {
70 | http.FileSystem
71 | }
72 |
73 | func (e embedFileSystem) Exists(prefix string, path string) bool {
74 | _, err := e.Open(path)
75 | if err != nil {
76 | return false
77 | }
78 | return true
79 | }
80 |
81 | func EmbedFolder(fsEmbed embed.FS, targetPath string) static.ServeFileSystem {
82 | fsys, err := fs.Sub(fsEmbed, targetPath)
83 | if err != nil {
84 | panic(err)
85 | }
86 | return embedFileSystem{
87 | FileSystem: http.FS(fsys),
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/Akka0/Iridium-NG
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/fatih/color v1.13.0
7 | github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19
8 | github.com/gin-gonic/gin v1.8.0
9 | github.com/google/gopacket v1.1.19
10 | github.com/jhump/protoreflect v1.12.0
11 | github.com/xtaci/kcp-go v5.4.20+incompatible
12 | )
13 |
14 | require (
15 | github.com/gin-contrib/sse v0.1.0 // indirect
16 | github.com/go-playground/locales v0.14.0 // indirect
17 | github.com/go-playground/universal-translator v0.18.0 // indirect
18 | github.com/go-playground/validator/v10 v10.11.0 // indirect
19 | github.com/goccy/go-json v0.9.7 // indirect
20 | github.com/golang/protobuf v1.5.2 // indirect
21 | github.com/json-iterator/go v1.1.12 // indirect
22 | github.com/klauspost/cpuid/v2 v2.0.6 // indirect
23 | github.com/klauspost/reedsolomon v1.9.16 // indirect
24 | github.com/leodido/go-urn v1.2.1 // indirect
25 | github.com/mattn/go-colorable v0.1.9 // indirect
26 | github.com/mattn/go-isatty v0.0.14 // indirect
27 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
28 | github.com/modern-go/reflect2 v1.0.2 // indirect
29 | github.com/pelletier/go-toml/v2 v2.0.1 // indirect
30 | github.com/pkg/errors v0.9.1 // indirect
31 | github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
32 | github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
33 | github.com/tjfoc/gmsm v1.4.1 // indirect
34 | github.com/ugorji/go/codec v1.2.7 // indirect
35 | github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
36 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
37 | golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
38 | golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect
39 | golang.org/x/text v0.3.7 // indirect
40 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
41 | google.golang.org/protobuf v1.28.0 // indirect
42 | gopkg.in/yaml.v2 v2.4.0 // indirect
43 | )
44 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
4 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
5 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
6 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
7 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
12 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
13 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
14 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
15 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
16 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
17 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
18 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
19 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
20 | github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19 h1:J2LPEOcQmWaooBnBtUDV9KHFEnP5LYTZY03GiQ0oQBw=
21 | github.com/gin-gonic/contrib v0.0.0-20201101042839-6a891bf89f19/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
22 | github.com/gin-gonic/gin v1.8.0 h1:4WFH5yycBMA3za5Hnl425yd9ymdw1XPm4666oab+hv4=
23 | github.com/gin-gonic/gin v1.8.0/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
24 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
25 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
26 | github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
27 | github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
28 | github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
29 | github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
30 | github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
31 | github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
32 | github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
33 | github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
34 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
35 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
36 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
37 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
38 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
39 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
40 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
41 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
42 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
43 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
44 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
45 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
46 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
47 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
48 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
49 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
50 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
51 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
52 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
53 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
54 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
55 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
56 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
57 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
58 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
59 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
60 | github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
61 | github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
62 | github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
63 | github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
64 | github.com/jhump/protoreflect v1.12.0 h1:1NQ4FpWMgn3by/n1X0fbeKEUxP1wBt7+Oitpv01HR10=
65 | github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
66 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
67 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
68 | github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
69 | github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
70 | github.com/klauspost/reedsolomon v1.9.16 h1:mR0AwphBwqFv/I3B9AHtNKvzuowI1vrj8/3UX4XRmHA=
71 | github.com/klauspost/reedsolomon v1.9.16/go.mod h1:eqPAcE7xar5CIzcdfwydOEdcmchAKAP/qs14y4GCBOk=
72 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
73 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
74 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
75 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
76 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
77 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
78 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
79 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
80 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
81 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
82 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
83 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
84 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
85 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
86 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
87 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
88 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
89 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
90 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
91 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
92 | github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
93 | github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
94 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
95 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
96 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
97 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
98 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
99 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
100 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
101 | github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
102 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
103 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
104 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
105 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
106 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
107 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
108 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
109 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
110 | github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
111 | github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
112 | github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
113 | github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
114 | github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
115 | github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
116 | github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
117 | github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
118 | github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
119 | github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
120 | github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
121 | github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
122 | github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
123 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
124 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
125 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
126 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
127 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
128 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
129 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
130 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
131 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
132 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
133 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
134 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
135 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
136 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
137 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
138 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
139 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
140 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
141 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
142 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
143 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
144 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
145 | golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
146 | golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
147 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
148 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
149 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
150 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
151 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
152 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
153 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
154 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
155 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
156 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
157 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
158 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
159 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
160 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
161 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
162 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
163 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
164 | golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0=
165 | golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
166 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
167 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
168 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
169 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
170 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
171 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
172 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
173 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
174 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
175 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
176 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
177 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
178 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
179 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
180 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
181 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
182 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
183 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
184 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
185 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
186 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
187 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
188 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
189 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
190 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
191 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
192 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
193 | google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
194 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
195 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
196 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
197 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
198 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
199 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
200 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
201 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
202 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
203 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
204 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
205 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
206 | google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
207 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
208 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
209 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
210 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
211 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
212 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
213 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
214 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
215 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
216 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
217 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
218 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
219 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
220 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
221 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
222 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
223 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "flag"
6 | "github.com/fatih/color"
7 | "github.com/google/gopacket/pcap"
8 | "io/ioutil"
9 | "log"
10 | "os"
11 | )
12 |
13 | type Config struct {
14 | DeviceName string `json:"deviceName"`
15 | PacketFilter []string `json:"packetFilter"`
16 | AutoSavePcapFiles bool `json:"autoSavePcapFiles"`
17 | }
18 |
19 | var config *Config
20 | var listDevice = flag.Bool("l", false, "List the network devices on this machine")
21 | var ip = flag.String("ip", "", "Designate the network devices to capture by IP")
22 |
23 | func main() {
24 | bytes, err := ioutil.ReadFile("./config.json")
25 | if err != nil {
26 | log.Fatalln("Could not load ./config.json", err)
27 | }
28 | err = json.Unmarshal(bytes, &config)
29 | if err != nil {
30 | log.Fatalln("Could not load ./config.json", err)
31 | }
32 | for packet := range config.PacketFilter {
33 | packetFilter[config.PacketFilter[packet]] = true
34 | }
35 |
36 | flag.Parse()
37 |
38 | if *listDevice {
39 | devices, err := pcap.FindAllDevs()
40 | if err != nil {
41 | log.Fatal(err)
42 | }
43 |
44 | log.Println(color.RedString("Name"), "\tDescription\t", color.CyanString("IP address"), "\tSubnet mask")
45 | for _, device := range devices {
46 | log.Println(color.RedString(device.Name), "\t", device.Description, "\t")
47 | for _, address := range device.Addresses {
48 | log.Println("\t\t\t", color.CyanString(address.IP.String()), "\t", address.Netmask)
49 | }
50 | }
51 | os.Exit(0)
52 | }
53 |
54 | if len(*ip) > 0 {
55 | devices, err := pcap.FindAllDevs()
56 | if err != nil {
57 | log.Fatal(err)
58 | }
59 |
60 | for _, device := range devices {
61 | for _, address := range device.Addresses {
62 | if address.IP.String() == *ip {
63 | log.Println("Device ", device.Name, " is chose")
64 | config.DeviceName = device.Name
65 | break
66 | }
67 | }
68 | }
69 | }
70 |
71 | go InitProto()
72 | startServer()
73 | }
74 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | BINARY=IridiumNG
2 |
3 | build-win:
4 | CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o build/${BINARY}_windows_amd64.exe
5 | build-darwin:
6 | CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o build/${BINARY}_darwin_amd64
7 | build-linux:
8 | CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o build/${BINARY}_linux_amd64
9 |
10 | build-arm64:
11 | CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o build/${BINARY}_darwin_arm64
12 | CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o build/${BINARY}_linux_arm64
13 |
14 | pre-build:
15 | mkdir build
16 | mkdir data
17 | cp ./config.json ./build/config.json
18 |
--------------------------------------------------------------------------------
/mt19937_64.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const N = 312
4 | const M = 156
5 | const MATRIX_A = 0xB5026F5AA96619E9
6 | const UPPER_MASK = 0xFFFFFFFF80000000
7 | const LOWER_MASK = 0x7FFFFFFF
8 |
9 | type MT19937_64 struct {
10 | array [312]uint64 //state vector
11 | index uint64 // array index
12 | }
13 |
14 | func New() *MT19937_64 {
15 | return &MT19937_64{
16 | index: N + 1,
17 | }
18 | }
19 |
20 | func (m *MT19937_64) Seed(seed int64) {
21 | m.array[0] = uint64(seed)
22 | for m.index = 1; m.index < N; m.index++ {
23 | m.array[m.index] = (6364136223846793005*(m.array[m.index-1]^(m.array[m.index-1]>>62)) + m.index)
24 | }
25 | }
26 |
27 | func (m *MT19937_64) Generate() int64 {
28 | return m.Int63()
29 | }
30 |
31 | func (m *MT19937_64) Int63() int64 {
32 | var i int
33 | var x uint64
34 | mag01 := []uint64{0, MATRIX_A}
35 | if m.index >= N {
36 | /* Initialize with a default Seed if Seed() not previously called */
37 | if m.index == N+1 {
38 | m.Seed(int64(5489))
39 | }
40 |
41 | for i = 0; i < N-M; i++ {
42 | x = (m.array[i] & UPPER_MASK) | (m.array[i+1] & LOWER_MASK)
43 | m.array[i] = m.array[i+(M)] ^ (x >> 1) ^ mag01[int(x&uint64(1))]
44 | }
45 | for ; i < N-1; i++ {
46 | x = (m.array[i] & UPPER_MASK) | (m.array[i+1] & LOWER_MASK)
47 | m.array[i] = m.array[i+(M-N)] ^ (x >> 1) ^ mag01[int(x&uint64(1))]
48 | }
49 | x = (m.array[N-1] & UPPER_MASK) | (m.array[0] & LOWER_MASK)
50 | m.array[N-1] = m.array[M-1] ^ (x >> 1) ^ mag01[int(x&uint64(1))]
51 | m.index = 0
52 |
53 | }
54 | x = m.array[m.index]
55 | m.index++
56 | x ^= (x >> 29) & 0x5555555555555555
57 | x ^= (x << 17) & 0x71D67FFFEDA60000
58 | x ^= (x << 37) & 0xFFF7EEE000000000
59 | x ^= (x >> 43)
60 |
61 | return int64(x)
62 | }
63 |
--------------------------------------------------------------------------------
/proto_service.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "github.com/jhump/protoreflect/desc"
7 | "github.com/jhump/protoreflect/desc/protoparse"
8 | "github.com/jhump/protoreflect/dynamic"
9 | "io/ioutil"
10 | "log"
11 | )
12 |
13 | var msgMap = make(map[string]*desc.MessageDescriptor)
14 | var packetIdMap map[uint16]string
15 | var packetNameMap = make(map[string]uint16)
16 | var protoParser = protoparse.Parser{}
17 |
18 | func InitProto() {
19 | packetIdFile, _ := ioutil.ReadFile("./data/packetIds.json")
20 | err := json.Unmarshal(packetIdFile, &packetIdMap)
21 | if err != nil {
22 | log.Fatalln("Could not load ./data/packetIds.json", err)
23 | }
24 |
25 | for k, v := range packetIdMap {
26 | packetNameMap[v] = k
27 | }
28 |
29 | protoParser.ImportPaths = []string{"./data/proto/"}
30 | for _, v := range packetIdMap {
31 | LoadProto(v)
32 | }
33 |
34 | }
35 |
36 | func LoadProto(protoName string) {
37 | fileDesc, err := protoParser.ParseFiles(protoName + ".proto")
38 | if err != nil {
39 | log.Println("Could not load proto file", protoName, err)
40 | return
41 | }
42 |
43 | msgMap[protoName] = fileDesc[0].FindMessage(protoName)
44 | }
45 |
46 | func GetProtoById(id uint16) *desc.MessageDescriptor {
47 | protoName, ok := packetIdMap[id]
48 | if !ok {
49 | return nil
50 | }
51 | return msgMap[protoName]
52 | }
53 |
54 | func GetProtoNameById(id uint16) string {
55 | protoName, ok := packetIdMap[id]
56 | if !ok {
57 | return ""
58 | }
59 | return protoName
60 | }
61 |
62 | func parseProto(id uint16, data []byte) (*dynamic.Message, error) {
63 | msg := GetProtoById(id)
64 | if msg == nil {
65 | return nil, errors.New("not found")
66 | }
67 | dMsg := dynamic.NewMessage(msg)
68 |
69 | err := dMsg.Unmarshal(data)
70 | return dMsg, err
71 | }
72 |
73 | func parseProtoToJson(id uint16, data []byte) string {
74 | dMsg, err := parseProto(id, data)
75 | if err != nil {
76 | return ""
77 | }
78 |
79 | marshalJSON, err := dMsg.MarshalJSON()
80 | if err != nil {
81 | return ""
82 | }
83 |
84 | return string(marshalJSON)
85 | }
86 |
87 | func parseProtoToInterface(id uint16, data []byte) *interface{} {
88 | object := parseProtoToJson(id, data)
89 |
90 | var result *interface{}
91 | err := json.Unmarshal([]byte(object), &result)
92 | if err != nil {
93 | return nil
94 | }
95 |
96 | return result
97 | }
98 |
--------------------------------------------------------------------------------
/sniffer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/base64"
5 | "encoding/binary"
6 | "encoding/json"
7 | "github.com/fatih/color"
8 | "github.com/google/gopacket"
9 | "github.com/google/gopacket/layers"
10 | "github.com/google/gopacket/pcap"
11 | "github.com/google/gopacket/pcapgo"
12 | "github.com/jhump/protoreflect/dynamic"
13 | "github.com/xtaci/kcp-go"
14 | "io/ioutil"
15 | "log"
16 | "os"
17 | "strconv"
18 | "strings"
19 | "time"
20 | )
21 |
22 | type Packet struct {
23 | Time int64 `json:"time"`
24 | FromServer bool `json:"fromServer"`
25 | PacketId uint16 `json:"packetId"`
26 | PacketName string `json:"packetName"`
27 | Object interface{} `json:"object"`
28 | Raw []byte `json:"raw"`
29 | }
30 |
31 | type UniCmdItem struct {
32 | PacketId uint16 `json:"packetId"`
33 | PacketName string `json:"packetName"`
34 | Object interface{} `json:"object"`
35 | Raw []byte `json:"raw"`
36 | }
37 |
38 | var getPlayerTokenRspPacketId uint16
39 | var unionCmdNotifyPacketId uint16
40 |
41 | var initialKey = make(map[uint16][]byte)
42 | var sessionKey []byte
43 |
44 | var captureHandler *pcap.Handle
45 | var kcpMap map[string]*kcp.KCP
46 | var packetFilter = make(map[string]bool)
47 | var pcapFile *os.File
48 |
49 | func openPcap(fileName string) {
50 | readKeys()
51 | var err error
52 | captureHandler, err = pcap.OpenOffline(fileName)
53 | if err != nil {
54 | log.Println("Could not open pacp file", err)
55 | return
56 | }
57 | startSniffer()
58 | }
59 |
60 | func openCapture() {
61 | readKeys()
62 | var err error
63 | captureHandler, err = pcap.OpenLive(config.DeviceName, 1500, true, -1)
64 | if err != nil {
65 | log.Println("Could not open capture", err)
66 | return
67 | }
68 |
69 | if config.AutoSavePcapFiles {
70 | pcapFile, err = os.Create(time.Now().Format("06-01-02 15.04.05") + ".pcapng")
71 | if err != nil {
72 | log.Println("Could not create pcapng file", err)
73 | }
74 | defer pcapFile.Close()
75 | }
76 |
77 | startSniffer()
78 | }
79 |
80 | func closeHandle() {
81 | if captureHandler != nil {
82 | captureHandler.Close()
83 | captureHandler = nil
84 | }
85 | if pcapFile != nil {
86 | pcapFile.Close()
87 | pcapFile = nil
88 | }
89 | }
90 |
91 | func readKeys() {
92 | var initialKeyJson map[uint16]string
93 | file, err := ioutil.ReadFile("./data/Keys.json")
94 | if err != nil {
95 | log.Fatal("Could not load initial key @ ./data/Keys.json #1", err)
96 | }
97 | err = json.Unmarshal(file, &initialKeyJson)
98 | if err != nil {
99 | log.Fatal("Could not load initial key @ ./data/Keys.json #2", err)
100 | }
101 |
102 | for k, v := range initialKeyJson {
103 | decode, _ := base64.RawStdEncoding.DecodeString(v)
104 | initialKey[k] = decode
105 | }
106 |
107 | getPlayerTokenRspPacketId = packetNameMap["GetPlayerTokenRsp"]
108 | unionCmdNotifyPacketId = packetNameMap["UnionCmdNotify"]
109 | }
110 |
111 | func startSniffer() {
112 | defer captureHandler.Close()
113 |
114 | err := captureHandler.SetBPFFilter("udp portrange 22101-22102")
115 | if err != nil {
116 | log.Println("Could not set the filter of capture")
117 | return
118 | }
119 |
120 | packetSource := gopacket.NewPacketSource(captureHandler, captureHandler.LinkType())
121 | packetSource.NoCopy = true
122 |
123 | kcpMap = make(map[string]*kcp.KCP)
124 |
125 | var pcapWriter *pcapgo.NgWriter
126 | if pcapFile != nil {
127 | pcapWriter, err = pcapgo.NewNgWriter(pcapFile, captureHandler.LinkType())
128 | if err != nil {
129 | log.Println("Could not create pcapng writer", err)
130 | }
131 | }
132 |
133 | for packet := range packetSource.Packets() {
134 | if pcapWriter != nil {
135 | err := pcapWriter.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
136 | if err != nil {
137 | log.Println("Could not write packet to pcap file", err)
138 | }
139 | }
140 |
141 | capTime := packet.Metadata().Timestamp
142 | data := packet.ApplicationLayer().Payload()
143 | udp := packet.TransportLayer().(*layers.UDP)
144 | fromServer := udp.SrcPort == 22101 || udp.SrcPort == 22102
145 |
146 | if len(data) <= 20 {
147 | handleSpecialPacket(data, fromServer, capTime)
148 | continue
149 | }
150 |
151 | handleKcp(data, fromServer, capTime)
152 | }
153 | }
154 |
155 | func handleKcp(data []byte, fromServer bool, capTime time.Time) {
156 | data = reformData(data)
157 | conv := binary.LittleEndian.Uint32(data[:4])
158 | key := strconv.Itoa(int(conv))
159 | if fromServer {
160 | key += "svr"
161 | } else {
162 | key += "cli"
163 | }
164 |
165 | if _, ok := kcpMap[key]; !ok {
166 | kcpInstance := kcp.NewKCP(conv, func(buf []byte, size int) {})
167 | kcpInstance.WndSize(1024, 1024)
168 | kcpMap[key] = kcpInstance
169 | }
170 | kcpInstance := kcpMap[key]
171 | _ = kcpInstance.Input(data, true, true)
172 |
173 | size := kcpInstance.PeekSize()
174 | for size > 0 {
175 | kcpBytes := make([]byte, size)
176 | kcpInstance.Recv(kcpBytes)
177 | handleProtoPacket(kcpBytes, fromServer, capTime)
178 | size = kcpInstance.PeekSize()
179 | }
180 | kcpInstance.Update()
181 | }
182 |
183 | func handleSpecialPacket(data []byte, fromServer bool, timestamp time.Time) {
184 | sessionKey = nil
185 | switch binary.BigEndian.Uint32(data[:4]) {
186 | case 0xFF:
187 | buildPacketToSend(data, fromServer, timestamp, 0, "Hamdshanke pls.")
188 | break
189 | case 404:
190 | buildPacketToSend(data, fromServer, timestamp, 0, "Disconnected.")
191 | break
192 | default:
193 | buildPacketToSend(data, fromServer, timestamp, 0, "Hamdshanke estamblished.")
194 | break
195 | }
196 | }
197 |
198 | func handleProtoPacket(data []byte, fromServer bool, timestamp time.Time) {
199 | key := binary.BigEndian.Uint16(data[:4])
200 | key = key ^ 0x4567
201 | var xorPad []byte
202 |
203 | if sessionKey != nil {
204 | xorPad = sessionKey
205 | } else {
206 | if len(initialKey[key]) == 0 {
207 | log.Println("Could not found initial key to decrypt", key)
208 | closeHandle()
209 | }
210 | xorPad = initialKey[key]
211 | }
212 | xorDecrypt(data, xorPad)
213 |
214 | packetId := binary.BigEndian.Uint16(data[2:4])
215 | var objectJson interface{}
216 |
217 | if packetId == getPlayerTokenRspPacketId {
218 | data, objectJson = handleGetPlayerTokenRspPacket(data, packetId, objectJson)
219 | } else if packetId == unionCmdNotifyPacketId {
220 | data, objectJson = handleUnionCmdNotifyPacket(data, packetId, objectJson)
221 | } else {
222 | data = removeHeaderForParse(data)
223 | objectJson = parseProtoToInterface(packetId, data)
224 | }
225 |
226 | buildPacketToSend(data, fromServer, timestamp, packetId, objectJson)
227 | }
228 |
229 | func handleGetPlayerTokenRspPacket(data []byte, packetId uint16, objectJson interface{}) ([]byte, interface{}) {
230 | data = removeMagic(data)
231 | dMsg, err := parseProto(packetId, data)
232 | if err != nil {
233 | log.Println("Could not parse GetPlayerTokenRspPacket proto", err)
234 | closeHandle()
235 | }
236 | oj, err := dMsg.MarshalJSON()
237 | if err != nil {
238 | log.Println("Could not parse GetPlayerTokenRspPacket proto", err)
239 | closeHandle()
240 | }
241 | err = json.Unmarshal(oj, &objectJson)
242 | if err != nil {
243 | log.Println("Could not parse GetPlayerTokenRspPacket proto", err)
244 | closeHandle()
245 | }
246 | seed := dMsg.GetFieldByName("secret_key_seed").(uint64)
247 | sessionKey = createXorPad(seed)
248 |
249 | return data, objectJson
250 | }
251 |
252 | func handleUnionCmdNotifyPacket(data []byte, packetId uint16, objectJson interface{}) ([]byte, interface{}) {
253 | data = removeHeaderForParse(data)
254 | dMsg, err := parseProto(packetId, data)
255 | if err != nil {
256 | log.Println("Could not parse UnionCmdNotify proto", err)
257 | }
258 |
259 | cmdList := dMsg.GetFieldByName("cmd_list").([]interface{})
260 | cmdListJson := make([]*UniCmdItem, len(cmdList))
261 | for i, item := range cmdList {
262 | msgItem := item.(*dynamic.Message)
263 | itemPacketId := uint16(msgItem.GetFieldByName("message_id").(uint32))
264 | itemData := msgItem.GetFieldByName("body").([]byte)
265 |
266 | childJson := parseProtoToInterface(itemPacketId, itemData)
267 |
268 | cmdListJson[i] = &UniCmdItem{
269 | PacketId: itemPacketId,
270 | PacketName: GetProtoNameById(itemPacketId),
271 | Object: childJson,
272 | Raw: itemData,
273 | }
274 | }
275 | objectJson = cmdListJson
276 | return data, objectJson
277 | }
278 |
279 | func buildPacketToSend(data []byte, fromSever bool, timestamp time.Time, packetId uint16, objectJson interface{}) {
280 | packet := &Packet{
281 | Time: timestamp.UnixMilli(),
282 | FromServer: fromSever,
283 | PacketId: packetId,
284 | PacketName: GetProtoNameById(packetId),
285 | Object: objectJson,
286 | Raw: data,
287 | }
288 |
289 | jsonResult, err := json.Marshal(packet)
290 | if err != nil {
291 | log.Println("Json marshal error", err)
292 | }
293 | logPacket(packet)
294 |
295 | if packetFilter[GetProtoNameById(packetId)] {
296 | return
297 | }
298 | sendStreamMsg(string(jsonResult))
299 | }
300 |
301 | func logPacket(packet *Packet) {
302 | from := "[Client]"
303 | if packet.FromServer {
304 | from = "[Server]"
305 | }
306 | forward := ""
307 | if strings.Contains(packet.PacketName, "Rsp") {
308 | forward = "<--"
309 | } else if strings.Contains(packet.PacketName, "Req") {
310 | forward = "-->"
311 | } else if strings.Contains(packet.PacketName, "Notify") && packet.FromServer {
312 | forward = "<-i"
313 | } else if strings.Contains(packet.PacketName, "Notify") {
314 | forward = "i->"
315 | }
316 |
317 | log.Println(color.GreenString(from),
318 | "\t",
319 | color.CyanString(forward),
320 | "\t",
321 | color.RedString(packet.PacketName),
322 | color.YellowString("#"+strconv.Itoa(int(packet.PacketId))),
323 | "\t",
324 | len(packet.Raw),
325 | )
326 |
327 | if packet.PacketId == unionCmdNotifyPacketId {
328 | logUnionCmdNotifyPacket(packet)
329 | }
330 | }
331 |
332 | func logUnionCmdNotifyPacket(packet *Packet) {
333 | uniCmdItem := packet.Object.([]*UniCmdItem)
334 |
335 | for i, item := range uniCmdItem {
336 | group := "├─"
337 | if i == len(uniCmdItem) {
338 | group = "└─"
339 | }
340 |
341 | log.Println("\t",
342 | "\t",
343 | color.CyanString(group),
344 | "\t",
345 | color.RedString(item.PacketName),
346 | color.YellowString("#"+strconv.Itoa(int(item.PacketId))),
347 | "\t",
348 | len(item.Raw),
349 | )
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/util.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "encoding/binary"
6 | )
7 |
8 | func removeMagic(data []byte) []byte {
9 | cut := data[5]
10 | data = data[8+2:] // Removes token + two byte magic
11 | data = data[0 : len(data)-2] // Removes two byte magic at the end
12 | data = data[cut:]
13 | return data
14 | }
15 |
16 | func removeHeaderForParse(data []byte) []byte {
17 | cut := data[6]
18 | data = removeMagic(data)
19 | return data[cut:]
20 | }
21 |
22 | func xorDecrypt(data []byte, key []byte) {
23 | for i := 0; i < len(data); i++ {
24 | data[i] = data[i] ^ key[i%len(key)]
25 | }
26 | }
27 |
28 | func reformData(data []byte) []byte {
29 | i := 0
30 | tokenSizeTotal := 0
31 | var messages [][]byte
32 | for i < len(data) {
33 | convId := data[i : i+4]
34 | remainingHeader := data[i+8 : i+28]
35 | contentLen := int(binary.LittleEndian.Uint32(data[i+24 : i+28]))
36 | content := data[i+28 : (i + 28 + contentLen)]
37 |
38 | formattedMessage := make([]byte, 24+contentLen)
39 | copy(formattedMessage, convId)
40 | copy(formattedMessage[4:], remainingHeader)
41 | copy(formattedMessage[24:], content)
42 | i += 28 + contentLen
43 | tokenSizeTotal += 4
44 | messages = append(messages, formattedMessage)
45 | }
46 |
47 | return bytes.Join(messages, []byte{})
48 | }
49 |
50 | func createXorPad(seed uint64) []byte {
51 | first := New()
52 | first.Seed(int64(seed))
53 | generator := New()
54 | generator.Seed(first.Generate())
55 | generator.Generate()
56 | xorPad := make([]byte, 4096)
57 |
58 | for i := 0; i < 4096; i += 8 {
59 | value := generator.Generate()
60 | binary.BigEndian.PutUint64(xorPad[i:i+8], uint64(value))
61 | }
62 | return xorPad
63 | }
64 |
--------------------------------------------------------------------------------