Files
IRC-kosmi-relay/KOSMI_IMAGE_UPLOAD.md
2025-11-01 10:40:53 -04:00

3.7 KiB

Kosmi Image Upload Protocol

Summary

Kosmi uses a simple HTTP POST to upload images, NOT the WebSocket. Images are uploaded to a dedicated CDN endpoint.

Upload Endpoint

POST https://img.kosmi.io/

Request Details

Method

POST

Headers

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary...
Origin: https://app.kosmi.io
Referer: https://app.kosmi.io/

Important: No authentication required! The endpoint accepts anonymous uploads.

Request Body

Standard multipart/form-data with a single field:

------WebKitFormBoundary...
Content-Disposition: form-data; name="file"; filename="blurt.jpg"
Content-Type: image/jpeg

[binary image data]
------WebKitFormBoundary...--

CORS

The endpoint has CORS enabled for https://app.kosmi.io:

Access-Control-Allow-Origin: https://app.kosmi.io

Response

Status

200 OK

Headers

Content-Type: application/json
Access-Control-Allow-Origin: https://app.kosmi.io

Response Body (CONFIRMED)

{
  "filename": "8d580b3a-905d-4bc9-909b-ccc6743edbdc.webp"
}

Note: The response contains only the filename, not the full URL. The full URL must be constructed as:

https://img.kosmi.io/{filename}

Example:

{
  "filename": "3460a8e1-fe19-4371-a735-64078e9923a4.webp"
}

→ Full URL: https://img.kosmi.io/3460a8e1-fe19-4371-a735-64078e9923a4.webp

Implementation Notes

For Go Client

  1. No authentication needed - This is a public upload endpoint
  2. Use standard multipart/form-data - Go's mime/multipart package
  3. Set CORS headers:
    • Origin: https://app.kosmi.io
    • Referer: https://app.kosmi.io/
  4. Parse JSON response to get the image URL
  5. Send the URL to Kosmi chat via the existing WebSocket sendMessage mutation

Workflow

  1. Generate room code PNG image (already implemented in roomcode_image.go)
  2. Upload PNG to https://img.kosmi.io/ via HTTP POST
  3. Parse response to get image URL
  4. Send message to Kosmi chat with the image URL
  5. Kosmi will automatically display the image as a thumbnail

Security Considerations

  • The endpoint is public (no auth required)
  • Files are likely rate-limited or size-limited
  • Images are served from img.kosmi.io CDN
  • The upload is CORS-protected (only works from app.kosmi.io origin)

Example Implementation (Pseudocode)

func UploadImageToKosmi(imageData []byte, filename string) (string, error) {
    // Create multipart form
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
    
    // Add file field
    part, err := writer.CreateFormFile("file", filename)
    if err != nil {
        return "", err
    }
    part.Write(imageData)
    writer.Close()
    
    // Create request
    req, err := http.NewRequest("POST", "https://img.kosmi.io/", body)
    if err != nil {
        return "", err
    }
    
    // Set headers
    req.Header.Set("Content-Type", writer.FormDataContentType())
    req.Header.Set("Origin", "https://app.kosmi.io")
    req.Header.Set("Referer", "https://app.kosmi.io/")
    
    // Send request
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    
    // Parse response
    var result struct {
        URL string `json:"url"`
    }
    json.NewDecoder(resp.Body).Decode(&result)
    
    return result.URL, nil
}

Testing

To test the upload, we can:

  1. Generate a test room code image
  2. Upload it to https://img.kosmi.io/
  3. Verify we get a URL back
  4. Send the URL to Kosmi chat
  5. Verify the image displays as a thumbnail

References

  • HAR capture: image_upload_HAR-sanitized.har (lines 3821-4110)
  • Upload request: Line 3910-4018
  • Upload response: Line 4019-4092