Skip to content

Repository files navigation

OpenDLink

English | 简体中文

Docker Cloudflare Workers License

Demo

A compact tool for turning OneDrive, iCloud Drive, and Google Drive public sharing links into permanent links, with optional API access to the current temporary download URL.

Features

  • Accepted Inputs: public sharing links from onedrive.live.com, 1drv.ms, sharepoint.com, icloud.com/iclouddrive, and drive.google.com
  • Official Microsoft Resolution Flow: prefers Shares API first, then falls back to Badger token, SharePoint drive bootstrap, or the official download endpoint when needed
  • Official Apple Resolution Flow: resolves iCloud Drive public shares through Apple's public CloudKit records/resolve endpoint and extracts the current asset download URL from the returned shared record
  • Google Drive Public Share Flow: resolves Google Drive public file shares through the public share page metadata and extracts the current download URL plus file information
  • Clean Web UI: generate, open, and copy permanent links directly from the page
  • Optional File Extension Input: keep the public link clean while preserving a readable suffix when needed
  • API Resolution: /api/resolve returns the current download URL plus file metadata
  • Unified Domain: backend provides the permanent-link domain without extra frontend configuration
  • Dual Deployment: Cloudflare Worker or Docker self-hosting

Note: this is not a full OneDrive API client. It implements the Microsoft-owned resolution path needed specifically for public file-share download links. For SharePoint Personal public links, it tries Shares API first; if the raw short link is rejected as an invalid shares key, it falls back to the anonymous share page's bootstrap data (driveUrl + driveAccessToken) and resolves the file through Microsoft's _api/v2.0/drives/... endpoint. Some short links may also use Microsoft's official download.aspx endpoint first.

Quick Start

Option 1: Docker Deployment

Deploy on any system that supports Docker (cloud server, local PC, NAS, Raspberry Pi, etc.):

# 1) Clone the repo, or extract the project archive first
git clone https://github.com/Shisly/OpenDLink.git
cd OpenDLink

# 2) Copy the example env file
cp .env.example .env

# Windows PowerShell:
# Copy-Item .env.example .env

# 3) Adjust .env if needed, then build and start
docker compose up -d --build

Or use pre-built image directly:

docker run -d -p 3000:3000 ghcr.io/shisly/opendlink:latest

Option 2: Cloudflare Worker

Use this when you want to deploy the whole service to Cloudflare, or when you want a dedicated Google Drive proxy Worker.

# 1) Clone the repo, or extract the project archive first
git clone https://github.com/Shisly/OpenDLink.git
cd OpenDLink

# 2) Install dependencies (Node.js 20+ required)
npm install

# 3) Build and validate the Worker bundle
npm run verify

Then deploy the generated dist/cloudflare-worker/worker.js file in Cloudflare Dashboard.


Directory Structure

.
├── dist/                # Generated runtime artifacts for Docker and Worker deployment
├── public/              # Frontend page
├── scripts/             # Build and verification scripts
├── src/                 # TypeScript source for server / worker / shared core
├── Dockerfile
├── docker-compose.yml
└── README.md

Notes:

  • In this project, dist/ is a release artifact, not a disposable cache directory, so it is intentionally committed
  • Docker builds use dist/server.js directly
  • Cloudflare Worker deployment uses dist/cloudflare-worker/worker.js directly
  • Each build overwrites the corresponding files under dist/; it does not keep appending extra generated copies

Docker Self-Hosting

Prerequisites

  • Docker Engine is installed
  • Docker Compose plugin is installed and docker compose version works
  • Your terminal is currently inside the project root, the directory that contains docker-compose.yml

Required Files

  • public/index.html
  • dist/server.js
  • dist/shared/opendlink-core.js
  • package.json
  • package-lock.json
  • Dockerfile
  • docker-compose.yml

Deployment Steps

  1. Download/clone the project and enter the project root:

    git clone https://github.com/Shisly/OpenDLink.git
    cd OpenDLink

    If you downloaded a ZIP instead:

    • Extract it first
    • Enter the extracted folder
    • Make sure docker-compose.yml is present in the current directory
  2. Copy the example environment file:

    cp .env.example .env

    Windows PowerShell:

    Copy-Item .env.example .env
  3. Edit .env and at least set your public domain:

    DOMAIN=https://opendlink.your-domain.com
    GOOGLE_PROXY_DOMAIN=https://your-google-proxy.workers.dev
    # Optional:
    # HOST_PORT=3000
    # CORS_ORIGIN=*
    # LOG=true

    Notes:

    • docker compose automatically reads the .env file from the project root
    • Values such as DOMAIN, GOOGLE_PROXY_DOMAIN, and HOST_PORT are first consumed by docker-compose.yml, then passed into the container
    • GOOGLE_PROXY_DOMAIN drives the frontend "Cloudflare Proxy" button for Google Drive
    • It should point to a separately deployed Cloudflare Worker proxy domain
    • If left empty, the frontend will hide that button
  4. If you changed source files such as src/server.ts or src/shared/*, regenerate runtime artifacts first:

    npm install
    npm run build:runtime

    Notes:

    • The Docker image packages the dist/ directory directly
    • If you only edit source files but do not rebuild dist/, the container will not include your latest code
  5. Start the service:

    docker compose up -d --build
  6. Check status:

    docker compose ps
    docker compose logs -f
  7. Verify locally first:

    • Open http://localhost:3000 in your browser
    • If you set HOST_PORT=8080, open http://localhost:8080
    • If you configured reverse proxy and HTTPS, then visit your final public domain instead

Reverse Proxy (Nginx)

server {
    listen 80;
    listen 443 ssl;
    server_name opendlink.your-domain.com;

    # SSL certificates (use certbot)
    # ssl_certificate     /etc/letsencrypt/live/opendlink.your-domain.com/fullchain.pem;
    # ssl_certificate_key /etc/letsencrypt/live/opendlink.your-domain.com/privkey.pem;

    location / {
        proxy_pass         http://127.0.0.1:3000;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}
certbot --nginx -d opendlink.your-domain.com
nginx -s reload

Notes:

  • If your host port is not 3000, update proxy_pass http://127.0.0.1:3000; to match the HOST_PORT value in .env
  • After Nginx is in front, DOMAIN in .env should be your final public HTTPS domain

API Routes

Path Description
GET / Frontend page for generating permanent links
GET /health Health check endpoint
GET /api/config Returns backend domain config
GET /api/resolve?shareUrl=... Returns the current download URL and file metadata through the public-share flow for OneDrive, iCloud Drive, or Google Drive
GET /1drv/{base64}.{ext} OneDrive / SharePoint permanent link. Resolves the latest upstream download URL and redirects to it
GET /icloud/{base64}.{ext} iCloud permanent link. Resolves the latest upstream download URL and proxies the file stream with filename headers
GET /google/{base64}.{ext} Google Drive permanent link. Resolves the latest upstream download URL and redirects to it
GET /google/proxy/{base64}.{ext} Google Drive proxy permanent link. Resolves the latest upstream download URL and proxies the file stream

Cloudflare Worker Deployment

Prerequisites

  • Node.js 20 or newer is installed
  • npm is installed
  • You have a Cloudflare account
  • Your terminal is currently inside the project root

Key Points

  • src/cloudflare-worker/worker.template.ts is the Worker template source
  • src/shared/opendlink-core.ts is the shared resolver source
  • dist/cloudflare-worker/worker.template.js is the generated runtime template
  • dist/cloudflare-worker/worker.js is the final deployable file
  • Do NOT manually edit anything under dist/
  • After modifying public/index.html, src/cloudflare-worker/worker.template.ts, or src/shared/opendlink-core.ts, rebuild and validate

Build & Validate

cd OpenDLink
npm install
npm run build:worker
npm run validate:worker

Full verification:

npm run verify

validate:worker checks:

  • No __HTML_PLACEHOLDER__ remaining in dist/cloudflare-worker/worker.js
  • ESM syntax is valid
  • default export.fetch exists
  • GET /api/config and GET / pass smoke tests

Dashboard Deployment Steps

  1. Enter the project root:

    cd OpenDLink
  2. Install dependencies:

    npm install
  3. If you modified pages or templates:

    npm run build:worker
    npm run validate:worker

    For a full end-to-end check, you can run:

    npm run verify
  4. Open dist/cloudflare-worker/worker.js

  5. Copy the full file into the Cloudflare Worker editor, then adjust the top config if needed:

    const CONFIG = {
      WORKER_DOMAIN: '',  // Leave empty for auto-detect, or set custom domain
      GOOGLE_PROXY_DOMAIN: '',  // Leave empty to hide the Google Drive Cloudflare proxy button
      CORS_ORIGIN: '*',
    };

    Notes:

    • WORKER_DOMAIN can stay empty if the Worker should use the current request host automatically
    • If you use a custom domain, write the full URL such as https://opendlink.your-domain.com
    • GOOGLE_PROXY_DOMAIN should point to the Worker domain dedicated to Google Drive proxy downloads
    • If this Worker itself is the dedicated Google Drive proxy site, WORKER_DOMAIN and GOOGLE_PROXY_DOMAIN can be the same domain
    • Always use full https://... URLs here, not bare hostnames
  6. Login to Cloudflare Dashboard

  7. Go to Workers & PagesCreateWorker

  8. Paste the full content of dist/cloudflare-worker/worker.js, then click Save and Deploy

  9. For a custom domain, open Worker settings and configure: TriggersAdd Custom Domain

  10. After deployment, verify these URLs first:

  • https://your-worker-domain/
  • https://your-worker-domain/api/config
  • If this Worker is a Google Drive proxy site, also test:
    • https://your-worker-domain/google/proxy/{base64}.{ext}

Permanent Link Format

https://your-worker.workers.dev/1drv/{base64ShareUrl}.mp4
https://your-worker.workers.dev/icloud/{base64ShareUrl}.mp4
https://your-worker.workers.dev/google/{base64ShareUrl}.mp4
https://your-worker.workers.dev/google/proxy/{base64ShareUrl}.mp4

Worker Related Files

File Purpose
src/cloudflare-worker/worker.template.ts Worker template source
src/shared/opendlink-core.ts Shared resolver source for Node and Worker
public/index.html Frontend page source
dist/cloudflare-worker/worker.template.js Runtime template generated by scripts/build-runtime.js
dist/cloudflare-worker/worker.js Generated deployable file
scripts/build-worker.js Builds runtime artifacts, injects public/index.html, and emits the Worker bundle
scripts/validate-worker.js Syntax and route validation

How It Works

User Browser              Backend (Worker/Docker)    Microsoft Official Endpoints
    │                            │                          │
    │── Open Page ──────────────>│                          │
    │<─ Return HTML ─────────────│                          │
    │                            │                          │
    │── GET /api/config ────────>│                          │
    │<─ { domain: "..." } ───────│                          │
    │                            │                          │
    │── GET /api/resolve ───────>│                          │
    │                            │── Call official flow ───>│
    │                            │   (Prefer Shares API)    │
    │                            │   (If 401/403, request   │
    │                            │    official Badger token │
    │                            │    and retry)            │
    │                            │   (If short link is      │
    │                            │    incompatible, switch  │
    │                            │    to official           │
    │                            │    download.aspx or      │
    │                            │    share-page Drive flow)│
    │                            │<─ Current CDN URL / file │
    │<─ Resolution result JSON ──│                          │
    │  (Page generates permanent link; API can return temp)│
    │                            │                          │
    │── GET /1drv/{base64}.mp4 ──────>│                          │
    │                            │── Call official flow ───>│
    │                            │<─ Current CDN URL ───────│
    │<─ 302 → CDN URL ───────────│                          │
    │  (Permanent Link: External URL stays constant)       │

FAQ

Q: Why can't I get the direct link?
A: Make sure the sharing link is set to "Anyone with the link can view" (public sharing), not password-protected or organization-only.

Q: Why do some public 1drv.ms links that used to return 401/403 work now?
A: Some of those links have actually been migrated to Microsoft's SharePoint Personal backend. Anonymous Shares API access is rejected there, but Microsoft's own frontend first obtains a Badger token and then retries the same Shares API. This project now follows that Microsoft API flow directly.

Q: Why can a 1drv.ms link resolve, but a my.sharepoint.com/:u:/g/personal/... link may fail if handled the same way?
A: 1drv.ms can still be treated by Microsoft's Shares API as a valid sharing URL key, so Badger retry is enough. The newer SharePoint Personal short link is different: the raw short URL is often rejected by Shares API as Invalid shares key. Microsoft’s share page then bootstraps an anonymous driveUrl and driveAccessToken, and uses the SharePoint/OneDrive drive API to fetch the same @content.downloadUrl. This project now follows that same fallback path.

Q: Does this tool implement the entire OneDrive API?
A: No. It only implements the official Microsoft path needed for “public file share -> downloadable URL” resolution. Shares API, Badger token, SharePoint share-page bootstrap, Drive API, and some official download endpoints are in scope. Upload, folder browsing, account auth, and broader OneDrive client features are not.

Q: How long is the temporary link returned by the API valid? A: Usually about 1 hour, controlled by OneDrive CDN signature. You need to re-fetch after expiration.

Q: Is the permanent link really permanent? A: More precisely, it is a permanent public entry rather than an immutable CDN URL. As long as the original sharing link remains valid, the permanent link resolves a fresh downloadable address on each visit, so the published URL can remain constant.

Q: Why not manually edit worker.js?
A: Embedding full HTML into Worker can easily introduce escaping or comment closure issues. The safest approach is to maintain src/cloudflare-worker/worker.template.ts, src/shared/opendlink-core.ts, and public/index.html, then generate the runtime files via script.

Q: Are performance requirements high for self-hosting?
A: Very low. The backend only calls the API once and returns a 302. Actual file traffic is still handled directly by OneDrive CDN. You can run it on a low-end VPS, Raspberry Pi, or even your local machine.


License

MIT License © 2026 Shisly

Releases

Packages

Contributors

Languages