API-dokumentáció
Küldjön fájlokat saját eszközeiből (szkriptek, programok, szerverek): hozzon létre egy átvitelt, töltse fel a fájlokat részletekben, kapja meg a linket.
Kulcs a Pro és Business csomagokban, a Fiókom › API menüben. Árak
Hitelesítés
Hozzon létre egy kulcsot a Fiókom › API menüben, és küldje el minden kérés Authorization fejlécében. Tartsa titokban: hozzáférést ad az átviteleihez. A törölt kulcs azonnal megszűnik működni.
Authorization: Bearer mlk_… Ha az eszköze vagy a tárhelye nem továbbítja az Authorization fejlécet, küldje ugyanazt a kulcsot az X-API-Key fejlécben:
X-API-Key: mlk_… Kulcsonként percenként 120 kérés. Méret, fájlok száma és elérhetőség: az Ön csomagja szerint.
Fájlküldés három lépésben
1. Az átvitel létrehozása
Adja meg a fájlok listáját (név és méret bájtban). A „recipients” mezővel minden címzett e-mailt kap; címzettek nélkül megosztható linket kap. Nem kötelező: „message”, „password”, „expire_days”, „delete_after_download”.
curl -X POST https://misi.link/api/v1/transfers \
-H "Authorization: Bearer $MISILINK_KEY" -H "Content-Type: application/json" \
-d '{"files": [{"name": "film.mov", "size": 5368709120}],
"recipients": ["client@example.com"], "message": "…", "expire_days": 14}' {"ok": true, "id": "aB3dE5fG", "token": "…", "url": "https://misi.link/aB3dE5fG",
"files": [{"id": 101, "name": "film.mov", "size": 5368709120}], "chunk_size": 8388608} 2. A fájlok feltöltése
Minden fájlt legfeljebb „chunk_size” bájtos részletekben küldjön, sorrendben: az „offset” az adott fájlból már fogadott bájtok száma. Megszakadás után a „status” megmutatja, honnan folytassa (409-es válasz: folytassa a „received” értéktől). Ha a tárhely vagy a tűzfal szűri a címeket, a pozíciót az X-Upload-Offset fejlécben küldje a cím helyett.
curl -X POST "https://misi.link/api/upload/chunk?id=aB3dE5fG&token=…&file=101&offset=0" \
-H "Content-Type: application/octet-stream" --data-binary @morceau-1.bin
# {"ok": true, "received": 8388608, "done": false}
curl "https://misi.link/api/upload/status?id=aB3dE5fG&token=…" 3. Befejezés
Ha minden fájl megérkezett, fejezze be: az átvitel elérhetővé válik, és az e-mailek elmennek. A link az első válaszban szereplő „url”. Ez a lépés kötelező. A szerver ezután eltárolja a fájlokat: eközben a „status” értéke „finalizing”. A teljesen megérkezett, de soha be nem fejezett átvitelt a rendszer 30 perc tétlenség után automatikusan befejezi.
curl -X POST https://misi.link/api/upload/complete -H "Content-Type: application/json" \
-d '{"id": "aB3dE5fG", "token": "…"}'
Közvetlen feltöltés a tárhelyre (nagy fájlokhoz ajánlott)
A „direct”: true beállítással a program közvetlenül a misi.link tárhelyére küldi a fájlt, a szerver megkerülésével: maximális sebesség, a végén pedig néhány másodperc alatt elérhető. Átvitelenként egy fájl (több fájl: tegye őket archívumba). E beállítás nélkül, vagy ha a válasz „direct”: null, a részeket a fenti módon, „chunk” hívással töltse fel.
- Hozza létre az átvitelt „direct”: true értékkel. A válasz megadja a „direct.part_size” (az egyes részek mérete, az utolsó rövidebb), a „direct.parts” (a részek száma) és a „direct.sign” értéket.
- Kérje le az aláírt címeket a „sign” hívással (azonosító, token és részszámok, hívásonként legfeljebb 100; 6 óráig érvényesek), majd minden részt küldjön egyszerű PUT kéréssel a saját címére, hitelesítési fejléc nélkül. A részek párhuzamosan is küldhetők, hiba után újraküldhetők.
- Zárja le a „complete” hívással. Ha egy rész hiányzik, a válasz „incomplete” a „missing” listával: küldje újra ezeket a részeket, majd hívja meg ismét a „complete”-et. Végpontok közötti titkosítás: minden rész egész titkosított szakaszok sorozata, sorrendben (lásd a példát).
curl -X POST https://misi.link/api/v1/transfers -H "Authorization: Bearer $MISILINK_KEY" -H "Content-Type: application/json" \
-d '{"files": [{"name": "film.mov", "size": 5368709120}], "direct": true}'
# {…, "direct": {"part_size": 16777216, "parts": 320, "total": 5368709120, "sign": "https://misi.link/api/upload/sign"}}
curl -X POST https://misi.link/api/upload/sign -H "Content-Type: application/json" \
-d '{"id": "aB3dE5fG", "token": "…", "parts": [1, 2, 3]}'
# {"ok": true, "urls": {"1": "https://…", "2": "https://…", "3": "https://…"}}
curl -X PUT -H "Content-Type: application/octet-stream" --data-binary @part-1.bin "https://…"
curl -X POST https://misi.link/api/upload/complete -H "Content-Type: application/json" -d '{"id": "aB3dE5fG", "token": "…"}'
# {"ok": false, "error": "incomplete", "missing": [2]}
Végpontok közötti titkosítás (nem kötelező)
A program küldés előtt titkosítja a fájlt: a misi.link csak olvashatatlan adatot kap és tárol. A kulcs soha nem kerül a szerverre: a linkben van, a „#” után. A címzett a böngészőjében tölti le és fejti vissza, a megszokott oldalon.
- Hozzon létre véletlenszerűen egy 16 bájtos kulcsot, majd hozza létre az átvitelt „e2e”: true értékkel és egyetlen fájllal (titkosítatlan mérete bájtban). Több fájlt előbb tegyen egy archívumba.
- Titkosító kulcs: a kulcs HKDF-SHA-256 értéke (só „misilink-e2e-v1”, info = az átvitel azonosítója, 16 bájt), AES-GCM-hez.
- Ossza a fájlt 4 MiB-os (4 194 304 bájtos) szakaszokra. Az i. szakasz: nonce = 4 nulla bájt, majd i 8 bájton (big-endian); kapcsolódó adat = i 8 bájton, majd 1 bájt (az utolsó szakasznál 1, egyébként 0). Minden titkosított szakasz 16 bájttal hosszabb: ezeket a bájtokat sorrendben töltse fel a „chunk” hívással (összesen „e2e.encrypted_size”), majd zárja le a „complete” hívással.
- Ajánlott: „e2e_verify” = a kulcs HKDF-SHA-256 értéke (ugyanaz a só, info „misilink-verify”, 32 bájt) base64url formában. Így a misi.link elutasítja a rossz kulccsal indított letöltést, anélkül hogy valaha ismerné a jót.
- Megosztható link: „url” + „#” + a kulcs base64url formában (22 karakter). Címzettek („recipients”) esetén adja meg az „e2e_key” értéket (a kulcsot): a misi.link lepecsételve őrzi, hogy beillessze az e-mailek linkjeibe.
curl -X POST https://misi.link/api/v1/transfers \
-H "Authorization: Bearer $MISILINK_KEY" -H "Content-Type: application/json" \
-d '{"files": [{"name": "film.mov", "size": 5368709120}], "e2e": true, "e2e_verify": "…"}'
# {"ok": true, "id": "aB3dE5fG", …, "e2e": {"segment": 4194304, "tag": 16, "encrypted_size": 5368729600, "version": 1}} Teljes példa Pythonban (cryptography könyvtár):
#!/usr/bin/env python3
# misi.link: end-to-end encrypted upload through the API (Python 3.8+, pip install cryptography)
# The file goes straight to the storage (signed URLs); if direct upload is unavailable, through "chunk".
# Usage: MISILINK_KEY=mlk_... python3 misilink_e2e.py file.mov [https://misi.link]
import base64, json, os, sys, urllib.request
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
SEG, SALT = 4 * 1024 * 1024, b'misilink-e2e-v1'
b64 = lambda b: base64.urlsafe_b64encode(b).rstrip(b'=').decode()
hkdf = lambda ikm, info, n: HKDF(SHA256(), n, SALT, info).derive(ikm)
def call(url, body=None, raw=None, headers=None, method=None, auth=True):
h = dict(headers or {})
if auth:
h['Authorization'] = 'Bearer ' + os.environ['MISILINK_KEY']
data = raw if raw is not None else (json.dumps(body).encode() if body is not None else None)
if data is not None:
h.setdefault('Content-Type', 'application/octet-stream' if raw is not None else 'application/json')
req = urllib.request.Request(url, data=data, headers=h, method=method or ('POST' if data is not None else 'GET'))
with urllib.request.urlopen(req, timeout=600) as r:
body = r.read()
return json.loads(body) if body[:1] == b'{' else {}
def segments(path, key, size):
n = max(1, -(-size // SEG))
with open(path, 'rb') as f:
for i in range(n):
last = i == n - 1
nonce = bytes(4) + i.to_bytes(8, 'big')
aad = i.to_bytes(8, 'big') + (b'\x01' if last else b'\x00')
yield key.encrypt(nonce, f.read(SEG), aad) # SEG bytes in, SEG + 16 bytes out
def send(path, base='https://misi.link'):
size = os.path.getsize(path)
secret = os.urandom(16) # the key: never sent to the server
verify = b64(hkdf(secret, b'misilink-verify', 32)) # lets the server recognise the right key
t = call(base + '/api/v1/transfers', {'files': [{'name': os.path.basename(path), 'size': size}],
'e2e': True, 'e2e_verify': verify, 'direct': True})
key = AESGCM(hkdf(secret, t['id'].encode(), 16))
auth = {'id': t['id'], 'token': t['token']}
d = t.get('direct')
if d: # straight to the storage: parts of d['part_size'] bytes
part, n, urls = b'', 0, {}
def put(n, data):
if str(n) not in urls:
urls.update(call(d['sign'], {**auth, 'parts': list(range(n, min(n + 100, d['parts'] + 1)))})['urls'])
call(urls[str(n)], raw=data, method='PUT', auth=False)
for seg in segments(path, key, size):
part += seg
if len(part) == d['part_size']:
n += 1; put(n, part); part = b''
if part:
n += 1; put(n, part)
else: # through the server
sent = 0
for seg in segments(path, key, size):
r = call(t['upload']['chunk'] + '?id=' + t['id'] + '&token=' + t['token'] + '&file=' + str(t['files'][0]['id']),
raw=seg, headers={'X-Upload-Offset': str(sent)})
sent = r['received']
call(t['upload']['complete'], auth)
return t['url'] + '#' + b64(secret) # the key travels after "#", only in the link
if __name__ == '__main__':
print(send(sys.argv[1], *(sys.argv[2:3] or [])))
Egyéb kérések
GET /api/v1/transfers- Az átvitelei, oldalanként 50 (?page=2…).
GET /api/v1/transfers/{id}- Egy átvitel: állapot, link, fájlok, letöltések száma, lejárati dátum.
DELETE /api/v1/transfers/{id}- Átvitel törlése (a link megszűnik működni).
GET /api/v1/me- A fiókja, csomagja és annak korlátai, a részletek mérete.
Dátumok ISO 8601 formátumban (UTC), méretek bájtban.
Válaszok és hibák
Minden válasz JSON, „ok” mezővel. Hiba esetén: „error” (rövid kód) és „message”. HTTP-kódok: 401 hiányzó vagy érvénytelen kulcs, 403 API nélküli csomag, 404 nem található, 409 rossz helyen lévő részlet, 422 elutasított kérés, 429 túl sok kérés (várjon egy percet).