# jdisk
A CLI tool for SJTU Netdisk
✅ **QR Code Authentication** - Simple and reliable authentication method
✅ **Complete File Operations** - Upload, download, list, navigate directories
✅ **Smart Session Management** - Persistent authentication with auto-renewal
---
## 🚀 **Quick Start**
### Installation
#### **Install from PyPI**
```bash
# Install via pip
pip install jdisk
jdisk --help
```
or
```bash
# Install via uv
uv tool install jdisk
jdisk --help
```
#### **Install from Source**
```bash
# Clone the repository
git clone https://github.com/chengjilai/jdisk.git
cd jdisk
# Install dependencies using pixi
pixi install
# Run the CLI tool directly
pixi run python jdisk.py --help
# Or create a symbolic link for system-wide access
chmod +x jdisk.py
ln -sf "$(pwd)/jdisk.py" ~/.local/bin/jdisk
# Verify installation
jdisk --help
```
### First Time Authentication
#### **QR Code Authentication** 📱
```bash
jdisk auth
```
**Process:**
1. QR code displayed in terminal
2. Scan with My SJTU mobile
---
## 📋 **Usage Examples**
### **Basic Operations**
```bash
# Authentication
jdisk auth # QR code authentication
# File Management
jdisk list # List root directory
jdisk list docs/ # List specific directory
jdisk ls # Short form of list
jdisk ls docs/ # List docs/ directory
# File Operations
jdisk upload file.txt # Upload to root directory
jdisk upload file.txt docs/ # Upload to specific directory
jdisk download file.txt # Download from root directory
jdisk download docs/file.txt # Download from specific directory
```
### **Advanced Usage**
```bash
# File operations with paths
jdisk upload ./local/file.txt /remote/path/
jdisk download /remote/file.txt ./local/
jdisk ls /folder/subfolder/
```
---
## 🌟 **Key Features**
### **Authentication**
- 💾 **Session Persistence**: Save and reuse authentication
- 🔄 **Auto-Refresh**: QR codes refresh to prevent expiration
### **File Operations**
- 📤 **Chunked Upload**: Efficient large file uploads with progress
- 📥 **Direct Download**: Fast downloads via S3 presigned URLs
- 📁 **Directory Navigation**: List and navigate directories
- 🔒 **Secure Connections**: HTTPS/TLS for all communications
### **User Experience**
- 🎨 **Terminal-Friendly**: Optimized for command-line usage
- 📱 **Mobile Support**: QR code scanning with mobile apps
---
## 🔧 **Authentication Method**
### **QR Code Authentication** 📱
**Features:**
- ✅ **Auto-refresh prevents expiration**
- ✅ **Server-provided security signatures**
- ✅ **Real-time WebSocket communication**
**How it works:**
1. Generate unique QR code with server signature
2. Scan with SJTU mobile app OR visit URL in browser
3. Login through SJTU JAccount website
4. System automatically captures authentication
5. QR code refreshes every 50 seconds to prevent expiration
**User Experience:**
📱 QR Code Authentication for SJTU Netdisk
📲 QR Code Generated:
[... QR code displayed in terminal ...]
---
## 📁 **Project Structure**
```
jdisk/
├── src/ # Source code directory
│ └── jdisk/ # Main package
│ ├── __init__.py # Package initialization
│ ├── auth.py # Authentication classes
│ ├── client.py # Main API client
│ ├── cli.py # CLI interface
│ ├── constants.py # API constants and URLs
│ ├── download.py # File download functionality
│ ├── exceptions.py # Custom exception classes
│ ├── models.py # Data models
│ ├── jdisk.py # Main CLI entry point
│ └── upload.py # File upload functionality
├── pyproject.toml # Package configuration
├── README.md
├── LICENSE
├── pixi.lock
├── .git
└── .gitignore
```
---
## 🛠️ **Dependencies**
```toml
[dependencies]
requests
qrcode
websocket-client
```
---
## 🏗️ **Technical Architecture**
### **QR Code Authentication Flow**
1. Extract UUID from SJTU login page
2. Establish WebSocket connection to jaccount.sjtu.edu.cn
3. Request QR code signature from server
4. Generate QR code with server-provided sig/ts values
5. Display QR code and URL in terminal
6. Monitor WebSocket for authentication events
7. Auto-refresh QR code every 50 seconds
8. Capture JAAuthCookie upon successful login
9. Complete authentication process
### **Authentication Security**
- **Server-provided signatures**: QR codes use proper cryptographic signatures from SJTU servers
- **Auto-refresh mechanism**: Prevents QR code expiration with periodic updates every 50 seconds
- **Secure WebSocket communication**: Real-time, encrypted communication channels
- **Temporary sessions**: Unique UUID for each authentication session
- **Automatic cleanup**: Sessions expire and clean up automatically
- **Correct Space ID Handling**: QR code authentication now generates sessions with proper `space3jvslhfm2b78t` space_id
### **Space Info API Handling**
The space info API has been **FIXED** to handle both response formats:
#### **Success Response Format (Current):**
```json
{
"libraryId": "smh2ax67srucy60s",
"spaceId": "space3jvslhfm2b78t",
"accessToken": "acctk019e278500mgm8qjucwuxta2j8swqemzv38ezcn2dzyqxm8ny2agd36pj6zfanmrhuh8way2vgjfs4asdph6s9b69z6zrjy27ulcmjdzqhv8yylpc56dbe8fc",
"expiresIn": 1800
}
```
#### **Response Analysis:**
- **Status Field Not Required**: The API doesn't return a `"status"` field in successful responses
- **Correct Format**: All required fields are directly available (`library_id`, `space_id`, `accessToken`)
- **Proper Access Token**: Access token in format `acctk...` (SJTU-specific token)
- **Expires In**: Token has 30-minute expiration for security
### **Session Structure**
#### **QR Code Authentication:**
```json
{
"ja_auth_cookie": "...",
"user_token": "...",
"library_id": "smh2...",
"space_id": "space...",
"access_token": "acctk...", // SJTU-specific access token
"username": "..."
}
```
### **File Upload Process**
Three-step chunked upload similar to AWS S3:
1. **Initiate**: Request upload permission and S3 URLs
2. **Upload**: Upload file chunks to S3 using provided credentials
3. **Confirm**: Verify upload completion and finalize file
### **File Download Process**
1. **Request**: Get download URL from SJTU Netdisk API
2. **Redirect**: Follow 302 redirect to S3 presigned URL
3. **Download**: Direct download from AWS S3 with progress tracking
---
## 🛠️ **API Reference**
### **Base Configuration**
```
Base URL: https://pan.sjtu.edu.cn
Authentication: JAAuthCookie + OAuth 2.0
Storage Backend: AWS S3-compatible (s3pan.jcloud.sjtu.edu.cn)
```
### **Authentication Endpoints**
#### **JAccount Authentication via JAAuthCookie**
The SJTU Netdisk uses JAAuthCookie for authentication, which can be obtained from browser cookies after logging into [pan.sjtu.edu.cn](https://pan.sjtu.edu.cn).
**Authentication Endpoint:**
```
GET https://jaccount.sjtu.edu.cn/oauth2/authorize/xpw8ou8y
```
**Token Exchange:**
```
POST https://pan.sjtu.edu.cn/user/v1/sign-in/verify-account-login/xpw8ou8y
```
**Request Body:**
```json
{
"credential": "{authorization_code}"
}
```
**Response:**
```json
{
"userToken": "128-character token",
"userId": "user_id",
"organizations": [
{
"libraryId": "library_id",
"orgUser": {
"nickname": "username"
}
}
]
}
```
**Personal Space Information:**
```
POST https://pan.sjtu.edu.cn/user/v1/space/1/personal
```
**Request Parameters:**
- `user_token`: 128-character user token
**Response:**
```json
{
"status": 0,
"libraryId": "library_id",
"spaceId": "space_id",
"accessToken": "access_token",
"expiresIn": 3600,
"message": "success"
}
```
### **File Upload API**
The upload process uses a three-step chunked approach similar to AWS S3 multipart upload.
#### **Step 1: Initiate Upload**
```
POST /api/v1/file/{library_id}/{space_id}/{path}?access_token={access_token}&multipart=null&conflict_resolution_strategy={strategy}
```
**Parameters:**
- `library_id`: User's library ID
- `space_id`: User's space ID
- `path`: Remote file path (URL encoded)
- `access_token`: Valid access token
- `multipart`: Fixed value "null"
- `conflict_resolution_strategy`: "rename" or "overwrite"
**Request Body:**
```json
{
"partNumberRange": [1, 2, 3]
}
```
**Response:**
```json
{
"confirmKey": "unique_confirmation_key",
"domain": "s3pan.jcloud.sjtu.edu.cn",
"path": "/tced-private-{random}-sjtu/{library_id}/{confirmKey}.txt",
"uploadId": "upload_id",
"parts": {
"1": {
"headers": {
"x-amz-date": "20251011T025800Z",
"x-amz-content-sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"authorization": "AWS4-HMAC-SHA256 Credential=..."
}
}
},
"expiration": "2025-10-11T03:13:00.569Z"
}
```
#### **Step 2: Upload Chunks**
```
PUT https://{domain}{path}?uploadId={uploadId}&partNumber={part_number}
```
**Headers:**
- `Content-Type`: `application/octet-stream`
- `Content-Length`: Chunk size in bytes
- `Accept`: `*/*`
- `Accept-Encoding`: `gzip, deflate, br`
- `Accept-Language`: `zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7`
- `x-amz-date`: From step 1 response
- `authorization`: From step 1 response
- `x-amz-content-sha256`: From step 1 response
**Request Body:**
Binary chunk data
#### **Step 3: Confirm Upload**
```
POST /api/v1/file/{library_id}/{space_id}/{confirmKey}?access_token={access_token}&confirm=null&conflict_resolution_strategy={strategy}
```
**Parameters:**
- `confirmKey`: From step 1 response
- `access_token`: Valid access token
- `confirm`: Fixed value "null"
- `conflict_resolution_strategy`: "rename" or "overwrite"
**Response:**
```json
{
"path": ["folder", "filename.txt"],
"name": "filename.txt",
"type": "file",
"creationTime": "2025-10-11T02:58:15.461Z",
"modificationTime": "2025-10-11T02:58:15.461Z",
"contentType": "text/plain",
"size": "391",
"eTag": "\"f255a82c43f56b46de4057cc5a393430-1\"",
"crc64": "11953636811276951993",
"metaData": {},
"isOverwritten": false,
"virusAuditStatus": 0,
"sensitiveWordAuditStatus": 0,
"previewByDoc": true,
"previewByCI": true,
"previewAsIcon": false,
"fileType": "text"
}
```
### **File Download API**
Downloads are handled through a redirect mechanism that provides AWS S3 presigned URLs.
#### **Download Request**
```
GET /api/v1/file/{library_id}/{space_id}/{path}?access_token={access_token}&download=true
```
**Parameters:**
- `library_id`: User's library ID
- `space_id`: User's space ID
- `path`: Remote file path
- `access_token`: Valid access token
- `download`: Fixed value "true"
**Response Flow:**
1. **302 Redirect** to AWS S3 presigned URL
2. **S3 URL** contains AWS4-HMAC-SHA256 signature with 2-hour expiration
3. **Direct Download** from `s3pan.jcloud.sjtu.edu.cn`
**S3 URL Pattern:**
```
https://s3pan.jcloud.sjtu.edu.cn/tced-private-{random}-sjtu/{library_id}/{file_id}.txt?
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&
X-Amz-Credential={credentials}&
X-Amz-Date={timestamp}&
X-Amz-Expires=7200&
X-Amz-Signature={signature}&
X-Amz-SignedHeaders=host&
response-content-disposition=inline%3B%20filename%2A%3DUTF-8%27%27{filename}
```
### **Directory Listing API**
#### **List Directory Contents**
```
GET /api/v1/directory/{library_id}/{space_id}/{path}?access_token={access_token}&page={page}&page_size={size}
```
**Parameters:**
- `library_id`: User's library ID
- `space_id`: User's space ID
- `path`: Directory path (use "/" for root)
- `access_token`: Valid access token
- `page`: Page number (default: 1)
- `page_size`: Items per page (default: 50)
**Response:**
```json
{
"path": [""],
"contents": [
{
"name": "filename.txt",
"type": "file",
"size": "391",
"modificationTime": "2025-10-11T03:03:14.000Z",
"isDir": false
}
],
"fileCount": 1,
"subDirCount": 0,
"totalNum": 1
}
```
---
### **Important Notes**
#### **Authentication Requirements**
- **Campus Network**: SJTU Netdisk typically requires connection through campus network or VPN
- **QR Code Authentication**: Scan with SJTU mobile app or visit authentication URL
- **Session Management**: Access tokens expire after 1 hour and need renewal
#### **Upload Constraints**
- **Chunk Size**: 4MB chunks recommended (4,194,304 bytes)
- **Maximum Chunks**: 50 chunks per upload session
- **File Size Limit**: ~200MB per file (50 chunks × 4MB)
- **Conflict Resolution**: Supports "rename" and "overwrite" strategies
#### **Download Features**
- **Streaming Support**: HTTP Range requests for partial downloads
- **Presigned URLs**: S3 URLs are valid for 2 hours
- **Integrity Verification**: CRC64 and ETag provided for file verification
- **Browser Compatible**: Uses standard HTTP redirects
---
## 🚨 **Troubleshooting**
### **QR Code Issues**
- **"QR code expired"**: Fixed! Auto-refresh prevents expiration
- **"Invalid signature"**: Fixed! Uses server-provided signatures
- **"WebSocket timeout**: Check network connection to SJTU servers
### **Authentication Issues**
- **"QR code scan failed"**: Try scanning again or visit the provided URL directly
- **"Session expired"**: Run `jdisk auth` to re-authenticate
- **"Network error"**: Ensure VPN or campus network connection
### **File Operation Issues**
- **"Upload failed"**: Check file size and network connectivity
- **"Download error"**: Verify file exists and permissions
- **"Permission denied"**: Re-authenticate with valid session
### **Error Handling**
- **Status Codes**: Standard HTTP status codes
- **Error Format**: JSON with `status`, `code`, `message`, and `requestId` fields
- **Common Errors**:
- `400 Bad Request`: Missing parameters or invalid data
- `401 Unauthorized`: Invalid or expired access token
- `404 Not Found`: File or directory does not exist
- `409 Conflict`: File already exists (when conflict_resolution_strategy is not set)
- `413 Payload Too Large`: File exceeds size limits
---
## 📈 **Development History**
### **Latest Updates**
- ✅ **QR Code Authentication**: Simple and reliable authentication method
- ✅ **Server-Provided Signatures**: QR codes use proper cryptographic signatures
- ✅ **Auto-Refresh Mechanism**: QR codes refresh every 50 seconds
- ✅ **Enhanced WebSocket Handling**: Improved real-time communication
- ✅ **Comprehensive Testing**: All features verified and working
---
## 📄 **License**
MIT License
---
## 🤝 **Contributing**
Contributions welcome! Please ensure:
- Code follows existing style
- Documentation is updated
- Features are backward compatible
---
**🎉 Enjoy using jdisk!**
For issues, feature requests, or questions, please check the documentation or create an issue.
Raw data
{
"_id": null,
"home_page": null,
"name": "jdisk",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "cli, shanghai-jiao-tong-university, storage",
"author": null,
"author_email": "chenghjilai <chengjilai@sjtu.edu.cn>",
"download_url": "https://files.pythonhosted.org/packages/22/f7/c3a59faa8047be172ea4edaa7ae42a85f7756069b4a043b5018c1f3bbce3/jdisk-0.1.8.tar.gz",
"platform": null,
"description": "# jdisk\n\nA CLI tool for SJTU Netdisk\n\n\n\u2705 **QR Code Authentication** - Simple and reliable authentication method\n\n\u2705 **Complete File Operations** - Upload, download, list, navigate directories\n\n\u2705 **Smart Session Management** - Persistent authentication with auto-renewal\n\n---\n\n## \ud83d\ude80 **Quick Start**\n\n### Installation\n\n#### **Install from PyPI**\n```bash\n# Install via pip\npip install jdisk\n\njdisk --help\n```\nor\n```bash\n# Install via uv\nuv tool install jdisk\n\njdisk --help\n```\n\n#### **Install from Source**\n```bash\n# Clone the repository\ngit clone https://github.com/chengjilai/jdisk.git\ncd jdisk\n\n# Install dependencies using pixi\npixi install\n\n# Run the CLI tool directly\npixi run python jdisk.py --help\n\n# Or create a symbolic link for system-wide access\nchmod +x jdisk.py\nln -sf \"$(pwd)/jdisk.py\" ~/.local/bin/jdisk\n\n# Verify installation\njdisk --help\n```\n\n### First Time Authentication\n\n#### **QR Code Authentication** \ud83d\udcf1\n```bash\njdisk auth\n```\n**Process:**\n1. QR code displayed in terminal\n2. Scan with My SJTU mobile\n\n---\n\n## \ud83d\udccb **Usage Examples**\n\n### **Basic Operations**\n\n```bash\n# Authentication\njdisk auth # QR code authentication\n\n# File Management\njdisk list # List root directory\njdisk list docs/ # List specific directory\njdisk ls # Short form of list\njdisk ls docs/ # List docs/ directory\n\n# File Operations\njdisk upload file.txt # Upload to root directory\njdisk upload file.txt docs/ # Upload to specific directory\njdisk download file.txt # Download from root directory\njdisk download docs/file.txt # Download from specific directory\n```\n\n### **Advanced Usage**\n\n```bash\n# File operations with paths\njdisk upload ./local/file.txt /remote/path/\njdisk download /remote/file.txt ./local/\njdisk ls /folder/subfolder/\n```\n\n\n---\n\n## \ud83c\udf1f **Key Features**\n\n### **Authentication**\n- \ud83d\udcbe **Session Persistence**: Save and reuse authentication\n- \ud83d\udd04 **Auto-Refresh**: QR codes refresh to prevent expiration\n\n### **File Operations**\n- \ud83d\udce4 **Chunked Upload**: Efficient large file uploads with progress\n- \ud83d\udce5 **Direct Download**: Fast downloads via S3 presigned URLs\n- \ud83d\udcc1 **Directory Navigation**: List and navigate directories\n- \ud83d\udd12 **Secure Connections**: HTTPS/TLS for all communications\n\n### **User Experience**\n- \ud83c\udfa8 **Terminal-Friendly**: Optimized for command-line usage\n- \ud83d\udcf1 **Mobile Support**: QR code scanning with mobile apps\n\n\n---\n\n## \ud83d\udd27 **Authentication Method**\n\n### **QR Code Authentication** \ud83d\udcf1\n\n**Features:**\n- \u2705 **Auto-refresh prevents expiration**\n- \u2705 **Server-provided security signatures**\n- \u2705 **Real-time WebSocket communication**\n\n**How it works:**\n1. Generate unique QR code with server signature\n2. Scan with SJTU mobile app OR visit URL in browser\n3. Login through SJTU JAccount website\n4. System automatically captures authentication\n5. QR code refreshes every 50 seconds to prevent expiration\n\n**User Experience:**\n\n\ud83d\udcf1 QR Code Authentication for SJTU Netdisk\n\ud83d\udcf2 QR Code Generated:\n[... QR code displayed in terminal ...]\n\n\n\n---\n\n## \ud83d\udcc1 **Project Structure**\n\n```\njdisk/\n\u251c\u2500\u2500 src/ # Source code directory\n\u2502 \u2514\u2500\u2500 jdisk/ # Main package\n\u2502 \u251c\u2500\u2500 __init__.py # Package initialization\n\u2502 \u251c\u2500\u2500 auth.py # Authentication classes\n\u2502 \u251c\u2500\u2500 client.py # Main API client\n\u2502 \u251c\u2500\u2500 cli.py # CLI interface\n\u2502 \u251c\u2500\u2500 constants.py # API constants and URLs\n\u2502 \u251c\u2500\u2500 download.py # File download functionality\n\u2502 \u251c\u2500\u2500 exceptions.py # Custom exception classes\n\u2502 \u251c\u2500\u2500 models.py # Data models\n\u2502 \u251c\u2500\u2500 jdisk.py # Main CLI entry point\n\u2502 \u2514\u2500\u2500 upload.py # File upload functionality\n\u251c\u2500\u2500 pyproject.toml # Package configuration\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 LICENSE\n\u251c\u2500\u2500 pixi.lock\n\u251c\u2500\u2500 .git\n\u2514\u2500\u2500 .gitignore\n\n```\n---\n\n\n## \ud83d\udee0\ufe0f **Dependencies**\n\n```toml\n[dependencies]\nrequests\nqrcode\nwebsocket-client\n```\n\n---\n\n## \ud83c\udfd7\ufe0f **Technical Architecture**\n\n### **QR Code Authentication Flow**\n\n1. Extract UUID from SJTU login page\n2. Establish WebSocket connection to jaccount.sjtu.edu.cn\n3. Request QR code signature from server\n4. Generate QR code with server-provided sig/ts values\n5. Display QR code and URL in terminal\n6. Monitor WebSocket for authentication events\n7. Auto-refresh QR code every 50 seconds\n8. Capture JAAuthCookie upon successful login\n9. Complete authentication process\n\n### **Authentication Security**\n\n- **Server-provided signatures**: QR codes use proper cryptographic signatures from SJTU servers\n- **Auto-refresh mechanism**: Prevents QR code expiration with periodic updates every 50 seconds\n- **Secure WebSocket communication**: Real-time, encrypted communication channels\n- **Temporary sessions**: Unique UUID for each authentication session\n- **Automatic cleanup**: Sessions expire and clean up automatically\n- **Correct Space ID Handling**: QR code authentication now generates sessions with proper `space3jvslhfm2b78t` space_id\n\n### **Space Info API Handling**\n\nThe space info API has been **FIXED** to handle both response formats:\n\n#### **Success Response Format (Current):**\n```json\n{\n \"libraryId\": \"smh2ax67srucy60s\",\n \"spaceId\": \"space3jvslhfm2b78t\",\n \"accessToken\": \"acctk019e278500mgm8qjucwuxta2j8swqemzv38ezcn2dzyqxm8ny2agd36pj6zfanmrhuh8way2vgjfs4asdph6s9b69z6zrjy27ulcmjdzqhv8yylpc56dbe8fc\",\n \"expiresIn\": 1800\n}\n```\n\n#### **Response Analysis:**\n- **Status Field Not Required**: The API doesn't return a `\"status\"` field in successful responses\n- **Correct Format**: All required fields are directly available (`library_id`, `space_id`, `accessToken`)\n- **Proper Access Token**: Access token in format `acctk...` (SJTU-specific token)\n- **Expires In**: Token has 30-minute expiration for security\n\n### **Session Structure**\n\n#### **QR Code Authentication:**\n```json\n{\n \"ja_auth_cookie\": \"...\",\n \"user_token\": \"...\",\n \"library_id\": \"smh2...\",\n \"space_id\": \"space...\",\n \"access_token\": \"acctk...\", // SJTU-specific access token\n \"username\": \"...\"\n}\n```\n\n\n\n### **File Upload Process**\n\nThree-step chunked upload similar to AWS S3:\n\n1. **Initiate**: Request upload permission and S3 URLs\n2. **Upload**: Upload file chunks to S3 using provided credentials\n3. **Confirm**: Verify upload completion and finalize file\n\n### **File Download Process**\n\n1. **Request**: Get download URL from SJTU Netdisk API\n2. **Redirect**: Follow 302 redirect to S3 presigned URL\n3. **Download**: Direct download from AWS S3 with progress tracking\n\n\n---\n\n## \ud83d\udee0\ufe0f **API Reference**\n\n### **Base Configuration**\n```\nBase URL: https://pan.sjtu.edu.cn\nAuthentication: JAAuthCookie + OAuth 2.0\nStorage Backend: AWS S3-compatible (s3pan.jcloud.sjtu.edu.cn)\n```\n\n### **Authentication Endpoints**\n\n#### **JAccount Authentication via JAAuthCookie**\nThe SJTU Netdisk uses JAAuthCookie for authentication, which can be obtained from browser cookies after logging into [pan.sjtu.edu.cn](https://pan.sjtu.edu.cn).\n\n**Authentication Endpoint:**\n```\nGET https://jaccount.sjtu.edu.cn/oauth2/authorize/xpw8ou8y\n```\n\n**Token Exchange:**\n```\nPOST https://pan.sjtu.edu.cn/user/v1/sign-in/verify-account-login/xpw8ou8y\n```\n\n**Request Body:**\n```json\n{\n \"credential\": \"{authorization_code}\"\n}\n```\n\n**Response:**\n```json\n{\n \"userToken\": \"128-character token\",\n \"userId\": \"user_id\",\n \"organizations\": [\n {\n \"libraryId\": \"library_id\",\n \"orgUser\": {\n \"nickname\": \"username\"\n }\n }\n ]\n}\n```\n\n**Personal Space Information:**\n```\nPOST https://pan.sjtu.edu.cn/user/v1/space/1/personal\n```\n\n**Request Parameters:**\n- `user_token`: 128-character user token\n\n**Response:**\n```json\n{\n \"status\": 0,\n \"libraryId\": \"library_id\",\n \"spaceId\": \"space_id\",\n \"accessToken\": \"access_token\",\n \"expiresIn\": 3600,\n \"message\": \"success\"\n}\n```\n\n### **File Upload API**\n\nThe upload process uses a three-step chunked approach similar to AWS S3 multipart upload.\n\n#### **Step 1: Initiate Upload**\n```\nPOST /api/v1/file/{library_id}/{space_id}/{path}?access_token={access_token}&multipart=null&conflict_resolution_strategy={strategy}\n```\n\n**Parameters:**\n- `library_id`: User's library ID\n- `space_id`: User's space ID\n- `path`: Remote file path (URL encoded)\n- `access_token`: Valid access token\n- `multipart`: Fixed value \"null\"\n- `conflict_resolution_strategy`: \"rename\" or \"overwrite\"\n\n**Request Body:**\n```json\n{\n \"partNumberRange\": [1, 2, 3]\n}\n```\n\n**Response:**\n```json\n{\n \"confirmKey\": \"unique_confirmation_key\",\n \"domain\": \"s3pan.jcloud.sjtu.edu.cn\",\n \"path\": \"/tced-private-{random}-sjtu/{library_id}/{confirmKey}.txt\",\n \"uploadId\": \"upload_id\",\n \"parts\": {\n \"1\": {\n \"headers\": {\n \"x-amz-date\": \"20251011T025800Z\",\n \"x-amz-content-sha256\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n \"authorization\": \"AWS4-HMAC-SHA256 Credential=...\"\n }\n }\n },\n \"expiration\": \"2025-10-11T03:13:00.569Z\"\n}\n```\n\n#### **Step 2: Upload Chunks**\n```\nPUT https://{domain}{path}?uploadId={uploadId}&partNumber={part_number}\n```\n\n**Headers:**\n- `Content-Type`: `application/octet-stream`\n- `Content-Length`: Chunk size in bytes\n- `Accept`: `*/*`\n- `Accept-Encoding`: `gzip, deflate, br`\n- `Accept-Language`: `zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7`\n- `x-amz-date`: From step 1 response\n- `authorization`: From step 1 response\n- `x-amz-content-sha256`: From step 1 response\n\n**Request Body:**\nBinary chunk data\n\n#### **Step 3: Confirm Upload**\n```\nPOST /api/v1/file/{library_id}/{space_id}/{confirmKey}?access_token={access_token}&confirm=null&conflict_resolution_strategy={strategy}\n```\n\n**Parameters:**\n- `confirmKey`: From step 1 response\n- `access_token`: Valid access token\n- `confirm`: Fixed value \"null\"\n- `conflict_resolution_strategy`: \"rename\" or \"overwrite\"\n\n**Response:**\n```json\n{\n \"path\": [\"folder\", \"filename.txt\"],\n \"name\": \"filename.txt\",\n \"type\": \"file\",\n \"creationTime\": \"2025-10-11T02:58:15.461Z\",\n \"modificationTime\": \"2025-10-11T02:58:15.461Z\",\n \"contentType\": \"text/plain\",\n \"size\": \"391\",\n \"eTag\": \"\\\"f255a82c43f56b46de4057cc5a393430-1\\\"\",\n \"crc64\": \"11953636811276951993\",\n \"metaData\": {},\n \"isOverwritten\": false,\n \"virusAuditStatus\": 0,\n \"sensitiveWordAuditStatus\": 0,\n \"previewByDoc\": true,\n \"previewByCI\": true,\n \"previewAsIcon\": false,\n \"fileType\": \"text\"\n}\n```\n\n### **File Download API**\n\nDownloads are handled through a redirect mechanism that provides AWS S3 presigned URLs.\n\n#### **Download Request**\n```\nGET /api/v1/file/{library_id}/{space_id}/{path}?access_token={access_token}&download=true\n```\n\n**Parameters:**\n- `library_id`: User's library ID\n- `space_id`: User's space ID\n- `path`: Remote file path\n- `access_token`: Valid access token\n- `download`: Fixed value \"true\"\n\n**Response Flow:**\n1. **302 Redirect** to AWS S3 presigned URL\n2. **S3 URL** contains AWS4-HMAC-SHA256 signature with 2-hour expiration\n3. **Direct Download** from `s3pan.jcloud.sjtu.edu.cn`\n\n**S3 URL Pattern:**\n```\nhttps://s3pan.jcloud.sjtu.edu.cn/tced-private-{random}-sjtu/{library_id}/{file_id}.txt?\nX-Amz-Algorithm=AWS4-HMAC-SHA256&\nX-Amz-Content-Sha256=UNSIGNED-PAYLOAD&\nX-Amz-Credential={credentials}&\nX-Amz-Date={timestamp}&\nX-Amz-Expires=7200&\nX-Amz-Signature={signature}&\nX-Amz-SignedHeaders=host&\nresponse-content-disposition=inline%3B%20filename%2A%3DUTF-8%27%27{filename}\n```\n\n### **Directory Listing API**\n\n#### **List Directory Contents**\n```\nGET /api/v1/directory/{library_id}/{space_id}/{path}?access_token={access_token}&page={page}&page_size={size}\n```\n\n**Parameters:**\n- `library_id`: User's library ID\n- `space_id`: User's space ID\n- `path`: Directory path (use \"/\" for root)\n- `access_token`: Valid access token\n- `page`: Page number (default: 1)\n- `page_size`: Items per page (default: 50)\n\n**Response:**\n```json\n{\n \"path\": [\"\"],\n \"contents\": [\n {\n \"name\": \"filename.txt\",\n \"type\": \"file\",\n \"size\": \"391\",\n \"modificationTime\": \"2025-10-11T03:03:14.000Z\",\n \"isDir\": false\n }\n ],\n \"fileCount\": 1,\n \"subDirCount\": 0,\n \"totalNum\": 1\n}\n```\n\n\n\n---\n\n### **Important Notes**\n\n#### **Authentication Requirements**\n- **Campus Network**: SJTU Netdisk typically requires connection through campus network or VPN\n- **QR Code Authentication**: Scan with SJTU mobile app or visit authentication URL\n- **Session Management**: Access tokens expire after 1 hour and need renewal\n\n#### **Upload Constraints**\n- **Chunk Size**: 4MB chunks recommended (4,194,304 bytes)\n- **Maximum Chunks**: 50 chunks per upload session\n- **File Size Limit**: ~200MB per file (50 chunks \u00d7 4MB)\n- **Conflict Resolution**: Supports \"rename\" and \"overwrite\" strategies\n\n#### **Download Features**\n- **Streaming Support**: HTTP Range requests for partial downloads\n- **Presigned URLs**: S3 URLs are valid for 2 hours\n- **Integrity Verification**: CRC64 and ETag provided for file verification\n- **Browser Compatible**: Uses standard HTTP redirects\n\n---\n\n## \ud83d\udea8 **Troubleshooting**\n\n### **QR Code Issues**\n- **\"QR code expired\"**: Fixed! Auto-refresh prevents expiration\n- **\"Invalid signature\"**: Fixed! Uses server-provided signatures\n- **\"WebSocket timeout**: Check network connection to SJTU servers\n\n### **Authentication Issues**\n- **\"QR code scan failed\"**: Try scanning again or visit the provided URL directly\n- **\"Session expired\"**: Run `jdisk auth` to re-authenticate\n- **\"Network error\"**: Ensure VPN or campus network connection\n\n### **File Operation Issues**\n- **\"Upload failed\"**: Check file size and network connectivity\n- **\"Download error\"**: Verify file exists and permissions\n- **\"Permission denied\"**: Re-authenticate with valid session\n\n### **Error Handling**\n- **Status Codes**: Standard HTTP status codes\n- **Error Format**: JSON with `status`, `code`, `message`, and `requestId` fields\n- **Common Errors**:\n - `400 Bad Request`: Missing parameters or invalid data\n - `401 Unauthorized`: Invalid or expired access token\n - `404 Not Found`: File or directory does not exist\n - `409 Conflict`: File already exists (when conflict_resolution_strategy is not set)\n - `413 Payload Too Large`: File exceeds size limits\n\n---\n\n## \ud83d\udcc8 **Development History**\n\n### **Latest Updates**\n- \u2705 **QR Code Authentication**: Simple and reliable authentication method\n- \u2705 **Server-Provided Signatures**: QR codes use proper cryptographic signatures\n- \u2705 **Auto-Refresh Mechanism**: QR codes refresh every 50 seconds\n- \u2705 **Enhanced WebSocket Handling**: Improved real-time communication\n- \u2705 **Comprehensive Testing**: All features verified and working\n\n---\n\n## \ud83d\udcc4 **License**\n\nMIT License\n\n---\n\n## \ud83e\udd1d **Contributing**\n\nContributions welcome! Please ensure:\n- Code follows existing style\n- Documentation is updated\n- Features are backward compatible\n\n---\n\n**\ud83c\udf89 Enjoy using jdisk!**\n\nFor issues, feature requests, or questions, please check the documentation or create an issue.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "SJTU Netdisk command line interface",
"version": "0.1.8",
"project_urls": {
"Homepage": "https://github.com/chengjilai/jdisk",
"Issues": "https://github.com/chengjilai/jdisk/issues",
"Repository": "https://github.com/chengjilai/jdisk"
},
"split_keywords": [
"cli",
" shanghai-jiao-tong-university",
" storage"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "44a9ba0bd9a591463b1e6c342e39dc335c5610c81d827be8d8e075d8b213fe44",
"md5": "683a9a69efbaa46ab56a508b9c219535",
"sha256": "719262c17487aea8df2c67aa34c4f22fef27c044064a10f930b7d61c86364fd2"
},
"downloads": -1,
"filename": "jdisk-0.1.8-py3-none-any.whl",
"has_sig": false,
"md5_digest": "683a9a69efbaa46ab56a508b9c219535",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 31442,
"upload_time": "2025-10-13T17:37:49",
"upload_time_iso_8601": "2025-10-13T17:37:49.804064Z",
"url": "https://files.pythonhosted.org/packages/44/a9/ba0bd9a591463b1e6c342e39dc335c5610c81d827be8d8e075d8b213fe44/jdisk-0.1.8-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "22f7c3a59faa8047be172ea4edaa7ae42a85f7756069b4a043b5018c1f3bbce3",
"md5": "eeb8680234ba621f398252f9bceca24b",
"sha256": "022552c0df3589380a4dafedbdb9d4a22a6f19552795c0b36ded49074cdbca7d"
},
"downloads": -1,
"filename": "jdisk-0.1.8.tar.gz",
"has_sig": false,
"md5_digest": "eeb8680234ba621f398252f9bceca24b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 25464,
"upload_time": "2025-10-13T17:37:51",
"upload_time_iso_8601": "2025-10-13T17:37:51.350689Z",
"url": "https://files.pythonhosted.org/packages/22/f7/c3a59faa8047be172ea4edaa7ae42a85f7756069b4a043b5018c1f3bbce3/jdisk-0.1.8.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-13 17:37:51",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "chengjilai",
"github_project": "jdisk",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "jdisk"
}