specprotocol 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +174 -0
- package/bin/specprotocol.js +136 -0
- package/dist/auth/microsoft.d.ts +23 -0
- package/dist/auth/microsoft.d.ts.map +1 -0
- package/dist/auth/microsoft.js +167 -0
- package/dist/auth/microsoft.js.map +1 -0
- package/dist/auth/offline.d.ts +20 -0
- package/dist/auth/offline.d.ts.map +1 -0
- package/dist/auth/offline.js +67 -0
- package/dist/auth/offline.js.map +1 -0
- package/dist/bot.d.ts +190 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +624 -0
- package/dist/bot.js.map +1 -0
- package/dist/entity/entity.d.ts +71 -0
- package/dist/entity/entity.d.ts.map +1 -0
- package/dist/entity/entity.js +157 -0
- package/dist/entity/entity.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/built-in/chat.d.ts +19 -0
- package/dist/plugins/built-in/chat.d.ts.map +1 -0
- package/dist/plugins/built-in/chat.js +62 -0
- package/dist/plugins/built-in/chat.js.map +1 -0
- package/dist/plugins/built-in/combat.d.ts +20 -0
- package/dist/plugins/built-in/combat.d.ts.map +1 -0
- package/dist/plugins/built-in/combat.js +42 -0
- package/dist/plugins/built-in/combat.js.map +1 -0
- package/dist/plugins/plugin-manager.d.ts +49 -0
- package/dist/plugins/plugin-manager.d.ts.map +1 -0
- package/dist/plugins/plugin-manager.js +76 -0
- package/dist/plugins/plugin-manager.js.map +1 -0
- package/dist/protocol/compression.d.ts +23 -0
- package/dist/protocol/compression.d.ts.map +1 -0
- package/dist/protocol/compression.js +85 -0
- package/dist/protocol/compression.js.map +1 -0
- package/dist/protocol/connection.d.ts +73 -0
- package/dist/protocol/connection.d.ts.map +1 -0
- package/dist/protocol/connection.js +212 -0
- package/dist/protocol/connection.js.map +1 -0
- package/dist/protocol/encryption.d.ts +29 -0
- package/dist/protocol/encryption.d.ts.map +1 -0
- package/dist/protocol/encryption.js +116 -0
- package/dist/protocol/encryption.js.map +1 -0
- package/dist/protocol/packet.d.ts +75 -0
- package/dist/protocol/packet.d.ts.map +1 -0
- package/dist/protocol/packet.js +140 -0
- package/dist/protocol/packet.js.map +1 -0
- package/dist/protocol/states/handshake.d.ts +19 -0
- package/dist/protocol/states/handshake.d.ts.map +1 -0
- package/dist/protocol/states/handshake.js +32 -0
- package/dist/protocol/states/handshake.js.map +1 -0
- package/dist/protocol/states/login.d.ts +77 -0
- package/dist/protocol/states/login.d.ts.map +1 -0
- package/dist/protocol/states/login.js +125 -0
- package/dist/protocol/states/login.js.map +1 -0
- package/dist/protocol/states/play.d.ts +187 -0
- package/dist/protocol/states/play.d.ts.map +1 -0
- package/dist/protocol/states/play.js +316 -0
- package/dist/protocol/states/play.js.map +1 -0
- package/dist/protocol/types.d.ts +210 -0
- package/dist/protocol/types.d.ts.map +1 -0
- package/dist/protocol/types.js +495 -0
- package/dist/protocol/types.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/events.d.ts +23 -0
- package/dist/utils/events.d.ts.map +1 -0
- package/dist/utils/events.js +44 -0
- package/dist/utils/events.js.map +1 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +47 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/vec3.d.ts +25 -0
- package/dist/utils/vec3.d.ts.map +1 -0
- package/dist/utils/vec3.js +66 -0
- package/dist/utils/vec3.js.map +1 -0
- package/dist/world/block.d.ts +39 -0
- package/dist/world/block.d.ts.map +1 -0
- package/dist/world/block.js +84 -0
- package/dist/world/block.js.map +1 -0
- package/dist/world/world.d.ts +55 -0
- package/dist/world/world.d.ts.map +1 -0
- package/dist/world/world.js +95 -0
- package/dist/world/world.js.map +1 -0
- package/docs/README.md +29 -0
- package/docs/api/auth.md +210 -0
- package/docs/api/bot.md +137 -0
- package/docs/api/events.md +166 -0
- package/docs/api/plugins.md +207 -0
- package/docs/api/protocol.md +129 -0
- package/docs/api/world.md +138 -0
- package/docs/first-bot.md +114 -0
- package/docs/getting-started.md +103 -0
- package/docs/guides/architecture.md +122 -0
- package/docs/guides/custom-plugins.md +211 -0
- package/docs/guides/raw-packets.md +80 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# SpecProtocol
|
|
2
|
+
|
|
3
|
+
A **Minecraft bot framework** built from scratch in TypeScript — a Mineflayer alternative with full protocol support for **Java Edition 1.21.4** (Protocol 769).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install specprotocol
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
- 🔌 **From-scratch protocol** — No dependency on `node-minecraft-protocol`
|
|
12
|
+
- 🔐 **Auth support** — Offline (cracked) & Microsoft (Device Code Flow)
|
|
13
|
+
- 🗜️ **Compression & Encryption** — Zlib + AES/CFB8 fully implemented
|
|
14
|
+
- 🌍 **World management** — Chunk sections, block access by coordinates
|
|
15
|
+
- 👾 **Entity tracking** — Spawn, remove, find nearest, spatial queries
|
|
16
|
+
- 🧩 **Plugin system** — Built-in chat & combat + custom plugin API
|
|
17
|
+
- 📦 **TypeScript-first** — Full type safety with typed events
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { createBot } from 'specprotocol';
|
|
23
|
+
|
|
24
|
+
const bot = await createBot({
|
|
25
|
+
host: 'localhost',
|
|
26
|
+
port: 25565,
|
|
27
|
+
username: 'MyBot',
|
|
28
|
+
auth: 'offline', // or 'microsoft'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
bot.on('spawn', () => {
|
|
32
|
+
console.log(`Spawned at ${bot.position}`);
|
|
33
|
+
bot.chat('Hello from SpecProtocol! 🤖');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
bot.on('chat', (message) => {
|
|
37
|
+
console.log(`Chat: ${message}`);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
bot.on('health', (health, food) => {
|
|
41
|
+
console.log(`Health: ${health}/20 | Food: ${food}/20`);
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 📖 API
|
|
46
|
+
|
|
47
|
+
### `createBot(options)`
|
|
48
|
+
|
|
49
|
+
| Option | Type | Default | Description |
|
|
50
|
+
|--------|------|---------|-------------|
|
|
51
|
+
| `host` | `string` | required | Server hostname |
|
|
52
|
+
| `port` | `number` | `25565` | Server port |
|
|
53
|
+
| `username` | `string` | required | Bot username |
|
|
54
|
+
| `auth` | `'offline' \| 'microsoft'` | `'offline'` | Authentication mode |
|
|
55
|
+
| `viewDistance` | `number` | `10` | Requested view distance |
|
|
56
|
+
| `logLevel` | `LogLevel` | `INFO` | Logging verbosity |
|
|
57
|
+
| `plugins` | `Plugin[]` | `[]` | Custom plugins to load |
|
|
58
|
+
|
|
59
|
+
### Bot Events
|
|
60
|
+
|
|
61
|
+
| Event | Payload | Description |
|
|
62
|
+
|-------|---------|-------------|
|
|
63
|
+
| `spawn` | — | Bot spawned in world |
|
|
64
|
+
| `chat` | `(message, isOverlay)` | Chat message received |
|
|
65
|
+
| `health` | `(health, food, saturation)` | Health updated |
|
|
66
|
+
| `death` | — | Bot died |
|
|
67
|
+
| `position` | `(Vec3)` | Position updated by server |
|
|
68
|
+
| `kicked` | `(reason)` | Kicked from server |
|
|
69
|
+
| `entitySpawn` | `(Entity)` | Entity spawned nearby |
|
|
70
|
+
| `entityRemove` | `(entityId)` | Entity removed |
|
|
71
|
+
| `blockUpdate` | `(x, y, z, stateId)` | Block changed |
|
|
72
|
+
| `error` | `(Error)` | Connection error |
|
|
73
|
+
| `end` | — | Disconnected |
|
|
74
|
+
|
|
75
|
+
### Bot Methods
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
bot.chat('Hello!') // Send chat message
|
|
79
|
+
bot.attack(entity) // Attack an entity
|
|
80
|
+
bot.setPosition(x, y, z) // Move to position
|
|
81
|
+
bot.lookAt(new Vec3(x, y, z)) // Look at coordinates
|
|
82
|
+
bot.dig(x, y, z) // Break a block
|
|
83
|
+
bot.setHeldItem(slot) // Select hotbar slot (0-8)
|
|
84
|
+
bot.disconnect() // Disconnect from server
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 🧩 Custom Plugins
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { createBot, type Plugin, type BotAPI } from 'specprotocol';
|
|
91
|
+
|
|
92
|
+
class MyPlugin implements Plugin {
|
|
93
|
+
name = 'my-plugin';
|
|
94
|
+
|
|
95
|
+
initialize(bot: BotAPI): void {
|
|
96
|
+
bot.on('spawn', () => {
|
|
97
|
+
console.log('Bot spawned!');
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
destroy(): void {
|
|
102
|
+
// Cleanup
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const bot = await createBot({
|
|
107
|
+
host: 'localhost',
|
|
108
|
+
username: 'Bot',
|
|
109
|
+
plugins: [new MyPlugin()],
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 🛠️ Low-Level Access
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { Connection, BufferReader, BufferWriter, PROTOCOL_VERSION } from 'specprotocol';
|
|
117
|
+
|
|
118
|
+
// Direct packet access
|
|
119
|
+
bot.on('rawPacket', (packet) => {
|
|
120
|
+
console.log(`Packet 0x${packet.id.toString(16)}: ${packet.data.length} bytes`);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Send raw packets
|
|
124
|
+
const writer = new BufferWriter();
|
|
125
|
+
writer.writeVarInt(42);
|
|
126
|
+
writer.writeString('hello');
|
|
127
|
+
bot.sendPacket(0x06, writer.toBuffer());
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 📂 Architecture
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
specprotocol/
|
|
134
|
+
├── src/
|
|
135
|
+
│ ├── index.ts # Public API exports
|
|
136
|
+
│ ├── bot.ts # Main Bot orchestrator
|
|
137
|
+
│ ├── types.ts # Shared types (BotAPI)
|
|
138
|
+
│ ├── auth/
|
|
139
|
+
│ │ ├── offline.ts # Offline auth & UUID generation
|
|
140
|
+
│ │ └── microsoft.ts # Microsoft OAuth (Device Code Flow)
|
|
141
|
+
│ ├── protocol/
|
|
142
|
+
│ │ ├── types.ts # VarInt, VarLong, BufferReader/Writer
|
|
143
|
+
│ │ ├── packet.ts # Packet framing, splitting, registry
|
|
144
|
+
│ │ ├── connection.ts # TCP connection manager
|
|
145
|
+
│ │ ├── compression.ts # Zlib compression
|
|
146
|
+
│ │ ├── encryption.ts # AES/CFB8 encryption
|
|
147
|
+
│ │ └── states/
|
|
148
|
+
│ │ ├── handshake.ts
|
|
149
|
+
│ │ ├── login.ts
|
|
150
|
+
│ │ └── play.ts
|
|
151
|
+
│ ├── entity/
|
|
152
|
+
│ │ └── entity.ts # Entity, PlayerEntity, EntityManager
|
|
153
|
+
│ ├── world/
|
|
154
|
+
│ │ ├── block.ts # ChunkSection, ChunkColumn
|
|
155
|
+
│ │ └── world.ts # World manager
|
|
156
|
+
│ ├── plugins/
|
|
157
|
+
│ │ ├── plugin-manager.ts
|
|
158
|
+
│ │ └── built-in/
|
|
159
|
+
│ │ ├── chat.ts
|
|
160
|
+
│ │ └── combat.ts
|
|
161
|
+
│ └── utils/
|
|
162
|
+
│ ├── vec3.ts # 3D vector class
|
|
163
|
+
│ ├── logger.ts # Leveled logger
|
|
164
|
+
│ └── events.ts # Typed event emitter
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## ⚙️ Requirements
|
|
168
|
+
|
|
169
|
+
- **Node.js** ≥ 18
|
|
170
|
+
- **Minecraft Java Edition** 1.21.4 (Protocol 769)
|
|
171
|
+
|
|
172
|
+
## 📄 License
|
|
173
|
+
|
|
174
|
+
MIT
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SpecProtocol CLI — Start a bot directly from the terminal.
|
|
5
|
+
*
|
|
6
|
+
* After `npm install specprotocol`, just run:
|
|
7
|
+
* specprotocol
|
|
8
|
+
*
|
|
9
|
+
* Or with arguments:
|
|
10
|
+
* specprotocol --host localhost --port 25565 --username MyBot
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { createBot } = require('../dist/index.js');
|
|
14
|
+
const readline = require('readline');
|
|
15
|
+
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
|
|
18
|
+
function getArg(name) {
|
|
19
|
+
const idx = args.indexOf(`--${name}`);
|
|
20
|
+
if (idx !== -1 && args[idx + 1]) return args[idx + 1];
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function ask(question) {
|
|
25
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
rl.question(question, (answer) => {
|
|
28
|
+
rl.close();
|
|
29
|
+
resolve(answer);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(' ╔═══════════════════════════════════╗');
|
|
37
|
+
console.log(' ║ 🎮 SpecProtocol v1.0 ║');
|
|
38
|
+
console.log(' ║ Minecraft Bot Framework (1.21.4) ║');
|
|
39
|
+
console.log(' ╚═══════════════════════════════════╝');
|
|
40
|
+
console.log('');
|
|
41
|
+
|
|
42
|
+
// Get config from args or ask interactively
|
|
43
|
+
const host = getArg('host') || await ask(' Sunucu adresi (localhost): ') || 'localhost';
|
|
44
|
+
const port = parseInt(getArg('port') || await ask(' Port (25565): ') || '25565');
|
|
45
|
+
const username = getArg('username') || await ask(' Bot adı (SpecBot): ') || 'SpecBot';
|
|
46
|
+
const auth = getArg('auth') || 'offline';
|
|
47
|
+
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(` → ${host}:${port} adresine "${username}" olarak bağlanılıyor...`);
|
|
50
|
+
console.log('');
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const bot = await createBot({
|
|
54
|
+
host,
|
|
55
|
+
port,
|
|
56
|
+
username,
|
|
57
|
+
auth,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
bot.on('spawn', () => {
|
|
61
|
+
console.log(` ✅ Dünyada doğuldu! Pozisyon: ${bot.position}`);
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log(' Komutlar:');
|
|
64
|
+
console.log(' say <mesaj> — Chat mesajı gönder');
|
|
65
|
+
console.log(' pos — Pozisyonu göster');
|
|
66
|
+
console.log(' health — Sağlık bilgisi');
|
|
67
|
+
console.log(' quit — Çıkış');
|
|
68
|
+
console.log('');
|
|
69
|
+
startRepl(bot);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
bot.on('chat', (message, isOverlay) => {
|
|
73
|
+
if (!isOverlay) {
|
|
74
|
+
console.log(` 💬 ${message}`);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
bot.on('health', (health, food) => {
|
|
79
|
+
if (health <= 0) console.log(' 💀 Bot öldü!');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
bot.on('kicked', (reason) => {
|
|
83
|
+
console.log(` 🚫 Sunucudan atıldı: ${reason}`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
bot.on('error', (err) => {
|
|
88
|
+
console.error(` ❌ Hata: ${err.message}`);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
bot.on('end', () => {
|
|
92
|
+
console.log(' 🔌 Bağlantı kesildi');
|
|
93
|
+
process.exit(0);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error(` ❌ Bağlantı kurulamadı: ${err.message}`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function startRepl(bot) {
|
|
103
|
+
const rl = readline.createInterface({
|
|
104
|
+
input: process.stdin,
|
|
105
|
+
output: process.stdout,
|
|
106
|
+
prompt: ' > ',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
rl.prompt();
|
|
110
|
+
|
|
111
|
+
rl.on('line', (line) => {
|
|
112
|
+
const input = line.trim();
|
|
113
|
+
|
|
114
|
+
if (input.startsWith('say ')) {
|
|
115
|
+
bot.chat(input.substring(4));
|
|
116
|
+
} else if (input === 'pos') {
|
|
117
|
+
console.log(` 📍 ${bot.position}`);
|
|
118
|
+
} else if (input === 'health') {
|
|
119
|
+
console.log(` ❤️ Can: ${bot.health}/20 | 🍖 Açlık: ${bot.food}/20`);
|
|
120
|
+
} else if (input === 'quit' || input === 'exit') {
|
|
121
|
+
bot.disconnect();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
} else if (input) {
|
|
124
|
+
console.log(' Bilinmeyen komut. Komutlar: say, pos, health, quit');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
rl.prompt();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
rl.on('close', () => {
|
|
131
|
+
bot.disconnect();
|
|
132
|
+
process.exit(0);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
main();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft Authentication for Minecraft Java Edition.
|
|
3
|
+
*
|
|
4
|
+
* Auth chain: Microsoft OAuth2 → Xbox Live → XSTS → Minecraft Services
|
|
5
|
+
*
|
|
6
|
+
* This implements the Device Code Flow (user opens a browser to authenticate).
|
|
7
|
+
*/
|
|
8
|
+
export interface MicrosoftAuthResult {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
username: string;
|
|
11
|
+
uuid: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Authenticate using Microsoft Device Code Flow.
|
|
15
|
+
* Returns a callback with the device code info, and a promise that resolves to the auth result.
|
|
16
|
+
*/
|
|
17
|
+
export declare function authenticateMicrosoft(onDeviceCode: (userCode: string, verificationUri: string) => void): Promise<MicrosoftAuthResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Join a server (session server authentication).
|
|
20
|
+
* Called after encrypting the shared secret, before sending Encryption Response.
|
|
21
|
+
*/
|
|
22
|
+
export declare function joinServer(accessToken: string, selectedProfile: string, serverHash: string): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=microsoft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.d.ts","sourceRoot":"","sources":["../../src/auth/microsoft.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CAChB;AAwCD;;;GAGG;AACH,wBAAsB,qBAAqB,CACvC,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,GAClE,OAAO,CAAC,mBAAmB,CAAC,CA0B9B;AA6HD;;;GAGG;AACH,wBAAsB,UAAU,CAC5B,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAef"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Microsoft Authentication for Minecraft Java Edition.
|
|
4
|
+
*
|
|
5
|
+
* Auth chain: Microsoft OAuth2 → Xbox Live → XSTS → Minecraft Services
|
|
6
|
+
*
|
|
7
|
+
* This implements the Device Code Flow (user opens a browser to authenticate).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.authenticateMicrosoft = authenticateMicrosoft;
|
|
11
|
+
exports.joinServer = joinServer;
|
|
12
|
+
// Microsoft Azure App Client ID for Minecraft
|
|
13
|
+
const CLIENT_ID = '00000000402b5328';
|
|
14
|
+
const AUTHORITY = 'https://login.live.com';
|
|
15
|
+
/**
|
|
16
|
+
* Authenticate using Microsoft Device Code Flow.
|
|
17
|
+
* Returns a callback with the device code info, and a promise that resolves to the auth result.
|
|
18
|
+
*/
|
|
19
|
+
async function authenticateMicrosoft(onDeviceCode) {
|
|
20
|
+
// Step 1: Get Device Code
|
|
21
|
+
const deviceCode = await requestDeviceCode();
|
|
22
|
+
onDeviceCode(deviceCode.user_code, deviceCode.verification_uri);
|
|
23
|
+
// Step 2: Poll for Microsoft Token
|
|
24
|
+
const msToken = await pollForToken(deviceCode);
|
|
25
|
+
// Step 3: Xbox Live Auth
|
|
26
|
+
const xboxToken = await authenticateXboxLive(msToken.access_token);
|
|
27
|
+
// Step 4: XSTS Token
|
|
28
|
+
const xstsToken = await authenticateXSTS(xboxToken.Token);
|
|
29
|
+
// Step 5: Minecraft Auth
|
|
30
|
+
const uhs = xstsToken.DisplayClaims.xui[0].uhs;
|
|
31
|
+
const mcAuth = await authenticateMinecraft(uhs, xstsToken.Token);
|
|
32
|
+
// Step 6: Get Minecraft Profile
|
|
33
|
+
const profile = await getMinecraftProfile(mcAuth.access_token);
|
|
34
|
+
return {
|
|
35
|
+
accessToken: mcAuth.access_token,
|
|
36
|
+
username: profile.name,
|
|
37
|
+
uuid: formatUUID(profile.id),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function requestDeviceCode() {
|
|
41
|
+
const response = await fetch(`${AUTHORITY}/oauth20_connect.srf`, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
44
|
+
body: new URLSearchParams({
|
|
45
|
+
client_id: CLIENT_ID,
|
|
46
|
+
scope: 'XboxLive.signin offline_access',
|
|
47
|
+
response_type: 'device_code',
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok)
|
|
51
|
+
throw new Error(`Device code request failed: ${response.status}`);
|
|
52
|
+
return response.json();
|
|
53
|
+
}
|
|
54
|
+
async function pollForToken(deviceCode) {
|
|
55
|
+
const intervalMs = (deviceCode.interval || 5) * 1000;
|
|
56
|
+
const expiresAt = Date.now() + deviceCode.expires_in * 1000;
|
|
57
|
+
while (Date.now() < expiresAt) {
|
|
58
|
+
await sleep(intervalMs);
|
|
59
|
+
const response = await fetch(`${AUTHORITY}/oauth20_token.srf`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
62
|
+
body: new URLSearchParams({
|
|
63
|
+
client_id: CLIENT_ID,
|
|
64
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
65
|
+
device_code: deviceCode.device_code,
|
|
66
|
+
}),
|
|
67
|
+
});
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
if (data.error === 'authorization_pending') {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (data.error) {
|
|
73
|
+
throw new Error(`Token polling error: ${data.error} — ${data.error_description}`);
|
|
74
|
+
}
|
|
75
|
+
return data;
|
|
76
|
+
}
|
|
77
|
+
throw new Error('Device code expired');
|
|
78
|
+
}
|
|
79
|
+
async function authenticateXboxLive(msAccessToken) {
|
|
80
|
+
const response = await fetch('https://user.auth.xboxlive.com/user/authenticate', {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
headers: {
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
'Accept': 'application/json',
|
|
85
|
+
},
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
Properties: {
|
|
88
|
+
AuthMethod: 'RPS',
|
|
89
|
+
SiteName: 'user.auth.xboxlive.com',
|
|
90
|
+
RpsTicket: `d=${msAccessToken}`,
|
|
91
|
+
},
|
|
92
|
+
RelyingParty: 'http://auth.xboxlive.com',
|
|
93
|
+
TokenType: 'JWT',
|
|
94
|
+
}),
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok)
|
|
97
|
+
throw new Error(`Xbox Live auth failed: ${response.status}`);
|
|
98
|
+
return response.json();
|
|
99
|
+
}
|
|
100
|
+
async function authenticateXSTS(xboxToken) {
|
|
101
|
+
const response = await fetch('https://xsts.auth.xboxlive.com/xsts/authorize', {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
'Accept': 'application/json',
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
Properties: {
|
|
109
|
+
SandboxId: 'RETAIL',
|
|
110
|
+
UserTokens: [xboxToken],
|
|
111
|
+
},
|
|
112
|
+
RelyingParty: 'rp://api.minecraftservices.com/',
|
|
113
|
+
TokenType: 'JWT',
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok)
|
|
117
|
+
throw new Error(`XSTS auth failed: ${response.status}`);
|
|
118
|
+
return response.json();
|
|
119
|
+
}
|
|
120
|
+
async function authenticateMinecraft(uhs, xstsToken) {
|
|
121
|
+
const response = await fetch('https://api.minecraftservices.com/authentication/login_with_xbox', {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { 'Content-Type': 'application/json' },
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
identityToken: `XBL3.0 x=${uhs};${xstsToken}`,
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
if (!response.ok)
|
|
129
|
+
throw new Error(`Minecraft auth failed: ${response.status}`);
|
|
130
|
+
return response.json();
|
|
131
|
+
}
|
|
132
|
+
async function getMinecraftProfile(accessToken) {
|
|
133
|
+
const response = await fetch('https://api.minecraftservices.com/minecraft/profile', {
|
|
134
|
+
headers: {
|
|
135
|
+
Authorization: `Bearer ${accessToken}`,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
if (!response.ok)
|
|
139
|
+
throw new Error(`Failed to get Minecraft profile: ${response.status}`);
|
|
140
|
+
return response.json();
|
|
141
|
+
}
|
|
142
|
+
function formatUUID(hex) {
|
|
143
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
144
|
+
}
|
|
145
|
+
function sleep(ms) {
|
|
146
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Join a server (session server authentication).
|
|
150
|
+
* Called after encrypting the shared secret, before sending Encryption Response.
|
|
151
|
+
*/
|
|
152
|
+
async function joinServer(accessToken, selectedProfile, serverHash) {
|
|
153
|
+
const response = await fetch('https://sessionserver.mojang.com/session/minecraft/join', {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: { 'Content-Type': 'application/json' },
|
|
156
|
+
body: JSON.stringify({
|
|
157
|
+
accessToken,
|
|
158
|
+
selectedProfile: selectedProfile.replace(/-/g, ''),
|
|
159
|
+
serverId: serverHash,
|
|
160
|
+
}),
|
|
161
|
+
});
|
|
162
|
+
if (response.status !== 204 && !response.ok) {
|
|
163
|
+
const errorText = await response.text();
|
|
164
|
+
throw new Error(`Failed to join server session: ${response.status} — ${errorText}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=microsoft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.js","sourceRoot":"","sources":["../../src/auth/microsoft.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline Authentication — for cracked/offline mode servers.
|
|
3
|
+
*
|
|
4
|
+
* In offline mode, no external auth is needed.
|
|
5
|
+
* The client just provides a username and generates an offline UUID.
|
|
6
|
+
*/
|
|
7
|
+
export interface OfflineProfile {
|
|
8
|
+
username: string;
|
|
9
|
+
uuid: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Generate an offline UUID from a username.
|
|
13
|
+
* Minecraft uses "OfflinePlayer:<username>" hashed with MD5, then sets version/variant bits.
|
|
14
|
+
*/
|
|
15
|
+
export declare function offlineUUID(username: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Create an offline profile from a username.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createOfflineProfile(username: string): OfflineProfile;
|
|
20
|
+
//# sourceMappingURL=offline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline.d.ts","sourceRoot":"","sources":["../../src/auth/offline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAKrE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Offline Authentication — for cracked/offline mode servers.
|
|
4
|
+
*
|
|
5
|
+
* In offline mode, no external auth is needed.
|
|
6
|
+
* The client just provides a username and generates an offline UUID.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.offlineUUID = offlineUUID;
|
|
43
|
+
exports.createOfflineProfile = createOfflineProfile;
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
/**
|
|
46
|
+
* Generate an offline UUID from a username.
|
|
47
|
+
* Minecraft uses "OfflinePlayer:<username>" hashed with MD5, then sets version/variant bits.
|
|
48
|
+
*/
|
|
49
|
+
function offlineUUID(username) {
|
|
50
|
+
const md5 = crypto.createHash('md5').update(`OfflinePlayer:${username}`).digest();
|
|
51
|
+
// Set version to 3 (name-based MD5)
|
|
52
|
+
md5[6] = (md5[6] & 0x0F) | 0x30;
|
|
53
|
+
// Set variant to IETF
|
|
54
|
+
md5[8] = (md5[8] & 0x3F) | 0x80;
|
|
55
|
+
const hex = md5.toString('hex');
|
|
56
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create an offline profile from a username.
|
|
60
|
+
*/
|
|
61
|
+
function createOfflineProfile(username) {
|
|
62
|
+
return {
|
|
63
|
+
username,
|
|
64
|
+
uuid: offlineUUID(username),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=offline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline.js","sourceRoot":"","sources":["../../src/auth/offline.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaH,kCAUC;AAKD,oDAKC;AA/BD,+CAAiC;AAOjC;;;GAGG;AACH,SAAgB,WAAW,CAAC,QAAgB;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAElF,oCAAoC;IACpC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACjC,sBAAsB;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAEjC,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/G,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAAC,QAAgB;IACjD,OAAO;QACH,QAAQ;QACR,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC;KAC9B,CAAC;AACN,CAAC"}
|