sipeed / NanoKVM

NanoKVM: Affordable, Multifunctional, Nano RISC-V IP-KVM
GNU General Public License v3.0
3.28k stars 60 forks source link

API Documentation #90

Open johncoles opened 1 month ago

johncoles commented 1 month ago

I see the code has now been shared so I may go through and do this myself, but it would be nice to have documentation for the HTTP API used.

I note so far that there is a request to /api/auth/login to perform the login, but the password is not sent as plaintext. Subsequent requests to the API seem to use a token that is set as a cookie.

Other endpoints include: GET /api/vm/gpio/led which returns the LED state: {"code":0,"msg":"success","data":{"pwr":false,"hdd":false}}

GET /api/storage/images/mounted {"code":0,"msg":"success","data":{"file":""}}

POST /api/vm/gpio with data like: {"type":"power","duration":800} will press the power button for 800ms. Returns: {"code":0,"msg":"success","data":null}

It would be great to have docs on how to use this to integrate in to other systems (I would like to add an integration in to Home Assistant for example) to control multiple machines.

wj-xiao commented 1 month ago

Please refer to these files for now. A more detailed document will be provided later.

patschi commented 1 month ago

I took some time reverse-engineering API calls and crafting a bash-curl-way of interacting with the API. Pretty surely also easy to adapt in other programming languages.

Note: Some API paths seems to mismatch between "reality" (NanoKVM with latest 2.0.9 as of today) and today's available code on GitHub: For example, /storage/image/mounted fails, while /storage/images/mounted works. I believe the code is newer than most recent publicly available firmware.

It does not include all available API calls (such as application which doesn't work as of today or scripts) as I could/want not test them. But they do offer API endpoints. With below, it should be possible to build something together yourself.

I thought it might be useful for others, so here we go:

AUTH

Note:

# Login to NanoKVM and receive token
# Adjust variables below
HOSTNAME="192.168.0.1"
USERNAME="admin"
PASSWORD="admin"

# Usually hardcoded and no need to change
PWSECKEY="nanokvm-sipeed-2024"

# Encrypt password via AES-256-CBC before sending to API
PASSENC=$(echo -n "$PASSWORD" | openssl enc -aes-256-cbc -base64 -salt -md md5 -pass pass:$PWSECKEY 2>/dev/null)
# Build JSON string for login, urlencode values as backend expects
AUTHJSON=$(jq -crnM --arg u "$USERNAME" --arg p "$PASSENC" '{"username":$u|@uri,"password":$p|@uri}')

# Send request via curl to NanoKVM
REQUEST=$(curl -s -X POST http://$HOSTNAME/api/auth/login -H 'Content-Type: application/json' --data-raw "$AUTHJSON")

# Parse token via jq from above request
TOKEN=$(echo $REQUEST | jq -r .data.token)
# Set cookie variable to be used by curl
COOKIE="nano-kvm-token=$TOKEN"

After this, below commands can be used.

GENERAL (named "VM" in code)

Get device info

# curl -s -b $COOKIE http://$HOSTNAME/api/vm/info
{"code":0,"msg":"success","data":{"ip":"<IP>","mdns":"kvm-<LAST 4 DIGITS OF MAC>.local","image":"2024-08-17-18-13-713161.img","firmware":"2.0.9","deviceKey":"<ID>"}}

Get GPIO LED state

# curl -s -b $COOKIE http://$HOSTNAME/api/vm/gpio/led
{"code":0,"msg":"success","data":{"pwr":true,"hdd":false}}

Trigger power switch

Note:

# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/vm/gpio -H "Content-Type: application/json" -d '{"type":"power","duration":800}'
{"code":0,"msg":"success","data":null}

STREAM

Get current image and save to image.jpg

Note: This uses ffmpeg to convert the mjpeg stream to a image with name image.jpg.

# curl -s -N -b $COOKIE http://$HOSTNAME/api/stream/mjpeg -o - | ffmpeg -y -i - -frames:v 1 -vcodec mjpeg image.jpg

If you want to do something fancy:

# tesseract image.jpg -
Warning: Invalid resolution 0 dpi. Using 70 instead.
Estimating resolution as 239
{C 8066 .3211711 vyos—configi39181: Configuration success
Welcome to VyOS — vyos ttyl

vyos login: vyos
[...]

Record the stream to x264-encoded file

Note:

# curl -s -N -b $COOKIE http://$HOSTNAME/api/stream/mjpeg -o - | ffmpeg -y -use_wallclock_as_timestamps 1 -f mjpeg -i - -an -t 30 -c:v libx264 -f mp4 output.mp4

Type text automatically

# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/hid/paste -H "Content-Type: application/json" -d '{"content": "this is a test"}'
{"code":0,"msg":"success","data":null}

# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/hid/paste -H "Content-Type: application/json" -d '{"content": "vyos\nvyos\n"}'
{"code":0,"msg":"success","data":null}

Examples: image image

Reset HID

# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/hid/reset
{"code":0,"msg":"success","data":null}

Get current frame detection state

Note: Not specifying -X makes it use GET by default.

# curl -s -b $COOKIE http://$HOSTNAME/api/stream/mjpeg/detect
{"code":0,"msg":"success","data":{"enabled":false}}

Toggle frame detection

# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/stream/mjpeg/detect
{"code":0,"msg":"success","data":{"enabled":true}}
# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/stream/mjpeg/detect
{"code":0,"msg":"success","data":{"enabled":false}}

STORAGE

Get available images

# curl -s -b $COOKIE http://$HOSTNAME/api/storage/images | jq -r
{
  "code": 0,
  "msg": "success",
  "data": {
    "files": [
      "/data/ubuntu-24.04-desktop-amd64.iso"
    ]
  }
}

Change mounted image

Note: Path is absolute path to ISO file

# curl -s -X POST -b $COOKIE http://$HOSTNAME/api/storage/image/mount -H "Content-Type: application/json" -d '{"file": "/data/ubuntu-24.04-desktop-amd64.iso"}'
{"code":0,"msg":"success","data":null}

Get currently mounted image

# curl -s -b $COOKIE http://$HOSTNAME/api/storage/images/mounted
{"code":0,"msg":"success","data":{"file":"/data/ubuntu-24.04-desktop-amd64.iso"}}

VIRTUAL DEVICES

Get current virtual devices state

# curl -s -b $COOKIE http://$HOSTNAME/api/vm/device/virtual
{"code":0,"msg":"success","data":{"network":true,"disk":true}}

Set/Toggle state of virtual device

Note: Use network or disk for device key

$ curl -s -X POST -b $COOKIE http://$HOSTNAME/api/vm/device/virtual -H "Content-Type: application/json" -d '{"device": "network"}'
{"code":0,"msg":"success","data":{"on":true}}

$ curl -s -X POST -b $COOKIE http://$HOSTNAME/api/vm/device/virtual -H "Content-Type: application/json" -d '{"device": "network"}'
{"code":0,"msg":"success","data":{"on":false}}
PatrickHuetter commented 1 month ago

Nice! Thanks for your work and sharing this!

FlorianHeigl commented 1 month ago

kudos for the tesseract example, more people should figure out stuff like this and do it!

FlorianHeigl commented 1 month ago

@wj-xiao Hi! is there a non-authenticated local API endpoint for scripts running on the device? Would be easier for sharing, unless someone says it's bad for security and I just didn't notice a problem there.

wj-xiao commented 3 weeks ago

@FlorianHeigl By default, APIs require authentication.

However, you can disable authentication by modifying the configuration file. Add one line authentication: disable to the configuration file /etc/kvm/server.yaml. And restart the service by /etc/init.d/S95nanokvm restart.

Please note that this will make the device insecure.

adamponi commented 1 week ago

Is there an API that will allow me to click? Also press keys

patschi commented 1 week ago

Is there an API that will allow me to click? Also press keys

Could not find a specific API call last time I checked, so I assume it's sent through the established websocket connection. Possible for sure, but way more tricky.