Compare commits
10 Commits
9e784bf689
...
892fc92251
Author | SHA1 | Date |
---|---|---|
Ashelyn Dawn | 892fc92251 | 6 months ago |
Zonoia | 4136ab7107 | 7 months ago |
Mike Jones | 915a891dd0 | 7 months ago |
Mike Jones | 204fff76fe | 7 months ago |
Zonoia | edc8be056d | 8 months ago |
Alt | 061c21a7f9 | 10 months ago |
Pwntheon | 59d936d19b | 10 months ago |
Pwntheon | d92ca5f82e | 10 months ago |
Alt | e67615b8b8 | 10 months ago |
Pwntheon | eb10125442 | 10 months ago |
@ -0,0 +1,8 @@
|
||||
# Copy files to docker container but ignore the following
|
||||
.*
|
||||
*.md
|
||||
src/
|
||||
DOCKERFILE
|
||||
# Following should not be on host but ignore anyway in case they exist for local debug
|
||||
node_modules/
|
||||
dist/
|
@ -0,0 +1,81 @@
|
||||
# Docker Setup Guide
|
||||
|
||||
This guide is mostly focused on Windows users (Mac instructions are given at some places).
|
||||
If you're a Linux/Mac/Other user, there's an expectancy that you know your system and it's peculiarities compared to Windows.
|
||||
|
||||
> This guide assumes you have a basic understanding of docker concepts and will be using Docker Desktop for Windows. If you want to use an alternative container management solution e.g. podman, there's an expectancy that you know your system and it's peculiarities compared to Docker Desktop.
|
||||
|
||||
**Use of docker is completely optional**. If you are not familiar with docker, or do not intend to run the file sync in a container, the [Beginners Guide](BeginnersGuide.md) manual setup is available.
|
||||
|
||||
If you need help with your particular system, feel free to ask for help in the Official Bitburner Discord.
|
||||
|
||||
## Running Remote API file sync in Docker
|
||||
|
||||
Docker is a virtualization layer that allows you to separate applications from underlying local host infrastructure, making application environments consistent and easier to manage.
|
||||
|
||||
You may want to use an isolated docker container for the Remote API instead of installing nodejs with the Remote API dependencies locally on your computer.
|
||||
|
||||
> This guide assumes you are familiar with docker fundamentals. You may need to modify these steps if using an alternative container management solution or if you want to include different docker options.
|
||||
|
||||
### 1. Backup your saved game (just in case)
|
||||
|
||||
- Bitburner > Options sidebar > click Export Game button.
|
||||
|
||||
### 2. Install Docker Desktop (if not already installed)
|
||||
- Go to https://www.docker.com/products/docker-desktop/
|
||||
- Download the version that's recommended for your OS.
|
||||
- Install it. Just click next, next, next, next, finish.
|
||||
|
||||
### 3. Clone or download this project from GitHub:
|
||||
- Go to https://github.com/bitburner-official/typescript-template
|
||||
- Click the green 'Code' button
|
||||
- If you are familiar with Git, clone the repository using the appropriate remote URL.
|
||||
- If you're unfamiliar with Git and have no intention to use it, download the ZIP and extract it somewhere on your computer.
|
||||
|
||||
### 4. Create `NetscriptDefinitions.d.ts` file for intellisense auto-complete
|
||||
|
||||
- The definitions file is used for 'intellisense' or auto-complete in text editors.
|
||||
- Create a file named `NetscriptDefinitions.d.ts` in your workspace. This is case sensitive. The contents of the file will be overwritten when you connect to bitburner so it doesn't matter what the file is, as long as it exists. The file should be in your project directory (same location as Dockerfile).
|
||||
- If the file does not exist, the volume bind mount in the docker command will create a directory named `NetscriptDefinitions.d.ts` instead of a file, which is not what we want!
|
||||
|
||||
|
||||
### 5. Run the bitburner-filesync docker container
|
||||
- Start a command prompt / PowerShell / terminal session in your project workspace and enter:
|
||||
|
||||
```docker build -t bitburner-typescript .```
|
||||
|
||||
- Enter the following command to run the bitburner-filesync container using the bitburner-typescript image created above:
|
||||
|
||||
```docker run --rm -d -v "$($pwd)/src:/app/src" -v "$($pwd)/NetscriptDefinitions.d.ts:/app/NetscriptDefinitions.d.ts" -p 12525:12525 --name bitburner-filesync bitburner-typescript```
|
||||
|
||||
> NOTE: In a PowerShell terminal the `$($pwd)` resolves to the current directory but you can modify the command with full file path to the src directory if required.
|
||||
|
||||
> NOTE: If you view the container logs they may show "`error TS2307: Cannot find module '@ns' or its corresponding type declarations`". This is fine, the `NetscriptDefinitions.d.ts` will be downloaded from the game once successfully connected to bitburner.
|
||||
|
||||
### 6. Start Bitburner and configure the remote API connection
|
||||
- Bitburner > Options sidebar > Remote API > type in the port `12525` and click connect. The icon should turn green and say it's online.
|
||||
> NOTE: Your firewall may yell at you; allow the connection.
|
||||
|
||||
### 7. Test that the connection works
|
||||
- In bitburner > terminal > enter `home` and then `ls` to list files on your home server.
|
||||
- You should see the `src/template.ts` file from your local workspace was automatically compiled to `template.js` and synced to the root of your `home` server in Bitburner.
|
||||
- In bitburner > terminal > enter `run template.js` and it should print the message `Hello Remote API!`.
|
||||
- Edit the message in the original `src/template.ts` file in your local workspace (using your preferred text editor) and and save the file.
|
||||
- The change should automatically sync to bitburner. In bitburner repeat `run template.js` and it should print your new message.
|
||||
|
||||
### 8. Thats it!
|
||||
- You can now make and edit the files in your local `src` workspace, and they will be synced to Bitburner automatically.
|
||||
> NOTE: do not use the internal bitburner 'nano' editor to change the files. You can use the 'nano' editor to view files but the remote API file sync is one way only, changes made in the bitburner 'nano' editor are not synced back to your local `src` workspace.
|
||||
- You may want to manually stop the docker filesync container when you are done playing bitburner:
|
||||
|
||||
`docker stop bitburner-filesync`
|
||||
|
||||
## Launching Bitburner, VS Code and the filesync docker container!
|
||||
|
||||
Playing bitburner with an external editor is cool, but each time you want to play bitburner you need to start the docker engine, run the filesync container, open your editor (e.g. VS Code) and your bitburner scripts workspace, and then launch the bitburner game. Phew! If only all that could be automated too...
|
||||
|
||||
You may want to create a PowerShell, python or other batch script that will launch everything with one click. This is beyond the scope of this guide given that everyone may have their own favourite text editor, container management solution, and custom installation directories.
|
||||
|
||||
|
||||
### For more information
|
||||
Read the readme of this https://github.com/bitburner-official/typescript-template and feel free to ask in Bitburner Discord channel `#external-editors:` https://discord.com/channels/415207508303544321/923428435618058311
|
@ -0,0 +1,20 @@
|
||||
# Use the official Node.js image as the base image
|
||||
FROM node:latest
|
||||
|
||||
# Create a working directory inside the container
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the package.json and package-lock.json to the container
|
||||
COPY package*.json ./
|
||||
|
||||
# Install application dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy all files to the container (but ignore paths specified in .dockerignore)
|
||||
COPY . /app/
|
||||
|
||||
# Expose the port the filesync will listen on
|
||||
EXPOSE 12525
|
||||
|
||||
# Run filesync watch when the container starts
|
||||
CMD npm run watch
|
@ -0,0 +1,5 @@
|
||||
export async function main(ns) {
|
||||
while (true) {
|
||||
await ns.hack(ns.getHostname());
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import ReactNamespace from 'react/index';
|
||||
import ReactDomNamespace from 'react-dom';
|
||||
|
||||
const React = window.React as typeof ReactNamespace;
|
||||
const ReactDOM = window.ReactDOM as typeof ReactDomNamespace;
|
||||
|
||||
export default React;
|
||||
export {
|
||||
ReactDOM
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { NS } from "@ns";
|
||||
import { getControllerState } from "/lib/types-and-constants";
|
||||
|
||||
export function printStatus(ns : NS) {
|
||||
const currentHackingLevel = ns.getHackingLevel()
|
||||
const {knownServers} = getControllerState(ns)
|
||||
|
||||
const numServers = knownServers.length
|
||||
const rootedServers = knownServers.filter(server => server.hasAdminRights).length
|
||||
const backdooredServers = knownServers.filter(server => server.backdoorInstalled).length
|
||||
const hackableServers = knownServers.filter(server => server.requiredHackingSkill && server.requiredHackingSkill <= currentHackingLevel).length
|
||||
|
||||
ns.print(`INFO: Current topology stats:\n`)
|
||||
ns.print(` - known: ${numServers}`)
|
||||
ns.print(` - hackable: ${hackableServers}`)
|
||||
ns.print(` - rooted: ${rootedServers}`)
|
||||
ns.print(` - backdoored: ${backdooredServers}`)
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { NS, Server } from "@ns"
|
||||
|
||||
const datafile = "/data-state.txt"
|
||||
|
||||
interface ControllerState {
|
||||
knownServers: Server[],
|
||||
assignments: {
|
||||
[droneHostname: string]: {
|
||||
targetHostname: string,
|
||||
attackMode: 'grow' | 'hack' | 'weaken',
|
||||
}
|
||||
},
|
||||
previousAssignments: {
|
||||
[droneHostname: string]: {
|
||||
targetHostname: string,
|
||||
attackMode: 'grow' | 'hack' | 'weaken',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getControllerState(ns : NS) : ControllerState {
|
||||
return JSON.parse(ns.read(datafile) || `{
|
||||
"knownServers": [],
|
||||
"assignments": {},
|
||||
"previousAssignments": {}
|
||||
}`)
|
||||
}
|
||||
|
||||
export function setControllerState(ns : NS, state : ControllerState) {
|
||||
ns.write(datafile, JSON.stringify(state), 'w')
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
import { NS } from "@ns";
|
||||
import { printStatus } from "/lib/status";
|
||||
|
||||
const phaseScripts = [
|
||||
'/tasks/01-discovery.js',
|
||||
'/tasks/02-breaching.js',
|
||||
'/tasks/03-targeting.js',
|
||||
'/tasks/04-propogation.js',
|
||||
]
|
||||
|
||||
const numPhases = phaseScripts.length
|
||||
let currentPhase = 0
|
||||
let pid = -1
|
||||
|
||||
export async function main(ns : NS) : Promise<void> {
|
||||
ns.disableLog('ALL')
|
||||
ns.tail()
|
||||
ns.resizeTail(600, 200)
|
||||
|
||||
while (true) {
|
||||
// Print status
|
||||
ns.clearLog()
|
||||
ns.print("currentPhase: " + phaseScripts[currentPhase])
|
||||
printStatus(ns)
|
||||
|
||||
// If current phase is still running, delay and continue
|
||||
if (ns.isRunning(pid)) {
|
||||
await ns.sleep(100)
|
||||
continue
|
||||
}
|
||||
|
||||
// Advance to next phase
|
||||
currentPhase = (currentPhase + 1) % numPhases
|
||||
pid = ns.run(phaseScripts[currentPhase])
|
||||
|
||||
// In case of error
|
||||
if (!pid) {
|
||||
ns.print("Error starting " + phaseScripts[currentPhase])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import { NS } from "@ns";
|
||||
import { getControllerState, setControllerState } from "/lib/types-and-constants";
|
||||
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns : NS) : Promise<void> {
|
||||
const datafileState = getControllerState(ns)
|
||||
|
||||
ns.print("INFO Starting automated scan . . .\n")
|
||||
let foundServers : string[] = []
|
||||
let serversToScan = datafileState.knownServers.map(server => server.hostname)
|
||||
|
||||
if(!serversToScan.length) {
|
||||
serversToScan = ['home']
|
||||
}
|
||||
|
||||
while (serversToScan.length) {
|
||||
const currentServer = serversToScan.shift() as string
|
||||
|
||||
if(foundServers.includes(currentServer)) continue
|
||||
|
||||
foundServers = [...foundServers, currentServer]
|
||||
|
||||
ns.print(`INFO Scanning from ${currentServer}\n`)
|
||||
const newVisibleServers = ns.scan(currentServer)
|
||||
.filter(server => !foundServers.includes(server))
|
||||
serversToScan = [...serversToScan, ...newVisibleServers]
|
||||
if(newVisibleServers.length > 0)
|
||||
ns.print(`SUCCESS - Discovered ${newVisibleServers.length} new servers to add to scan list\n`)
|
||||
}
|
||||
|
||||
datafileState.knownServers = foundServers.map(ns.getServer)
|
||||
setControllerState(ns, datafileState)
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
import { NS } from "@ns";
|
||||
import { getControllerState, setControllerState } from "/lib/types-and-constants";
|
||||
|
||||
export async function main(ns : NS) : Promise<void> {
|
||||
const datafileState = getControllerState(ns)
|
||||
const {knownServers} = datafileState
|
||||
|
||||
const portConfigs = [{
|
||||
openProperty: 'sshPortOpen',
|
||||
program: 'BruteSSH.exe',
|
||||
func: ns.brutessh
|
||||
}, {
|
||||
openProperty: 'ftpPortOpen',
|
||||
program: 'FTPCrack.exe',
|
||||
func: ns.ftpcrack
|
||||
}, {
|
||||
openProperty: 'sqlPortOpen',
|
||||
program: 'SQLInject.exe',
|
||||
func: ns.sqlinject
|
||||
}, {
|
||||
openProperty: 'httpPortOpen',
|
||||
program: 'HTTPWorm.exe',
|
||||
func: ns.httpworm
|
||||
}, {
|
||||
openProperty: 'smtpPortOpen',
|
||||
program: 'relaySMTP.exe',
|
||||
func: ns.relaysmtp
|
||||
}]
|
||||
|
||||
for (const server of knownServers) {
|
||||
if (server.hostname === 'home' || server.hasAdminRights)
|
||||
continue
|
||||
|
||||
const requiredPorts = server.numOpenPortsRequired ?? 0
|
||||
const alreadyOpen = server.openPortCount ?? 0
|
||||
const openablePorts = portConfigs.filter(port =>
|
||||
!(server as any)[port.openProperty]
|
||||
&& ns.fileExists(port.program))
|
||||
const numberCanOpen = openablePorts.length
|
||||
|
||||
if (alreadyOpen + numberCanOpen < requiredPorts) {
|
||||
ns.print(`WARN: Unable to nuke ${server.hostname}, cannot open enough ports (${alreadyOpen} + ${numberCanOpen} < ${requiredPorts})`)
|
||||
continue
|
||||
}
|
||||
|
||||
for (const port of openablePorts) {
|
||||
ns.tprint(`INFO: Opening ${port.openProperty.replace('PortOpen', '')} on ${server.hostname}`)
|
||||
port.func(server.hostname);
|
||||
(server as any)[port.openProperty] = true
|
||||
}
|
||||
|
||||
ns.tprint(`SUCCESS: Nuking ${server.hostname}`)
|
||||
ns.nuke(server.hostname)
|
||||
|
||||
server.hasAdminRights = true
|
||||
}
|
||||
|
||||
setControllerState(ns, {
|
||||
...datafileState,
|
||||
knownServers
|
||||
})
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import { NS } from "@ns";
|
||||
|
||||
export async function main(ns : NS) : Promise<void> {
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { NS } from "@ns";
|
||||
import { getControllerState } from "/lib/types-and-constants";
|
||||
|
||||
export async function main(ns : NS) : Promise<void> {
|
||||
const {knownServers} = getControllerState(ns)
|
||||
const playerHackingSkill = ns.getHackingLevel()
|
||||
|
||||
for (const server of knownServers) {
|
||||
if(!server.hasAdminRights || server.hostname === 'home')
|
||||
continue
|
||||
|
||||
if(server.requiredHackingSkill > playerHackingSkill)
|
||||
continue
|
||||
|
||||
ns.scp('auto-hack.js', server.hostname)
|
||||
const ramCost = ns.getScriptRam('auto-hack.js')
|
||||
const ramAvail = server.maxRam - server.ramUsed
|
||||
const numThreads = Math.floor(ramAvail / ramCost)
|
||||
|
||||
if (numThreads < 1)
|
||||
continue
|
||||
|
||||
ns.exec('auto-hack.js', server.hostname, numThreads)
|
||||
}
|
||||
await ns.sleep(10000)
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import { NS } from "@ns";
|
||||
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
ns.tprint("Hello Remote API!");
|
||||
}
|
Loading…
Reference in New Issue