ultisuite-backend/internal/meet/meet.go
R3D347HR4Y 1d063237b9
Some checks are pending
CI / Go tests (push) Waiting to run
CI / Integration tests (push) Waiting to run
CI / DB migrations (push) Waiting to run
feat(transcription): integrate Faster Whisper for Jitsi transcriptions
- Added support for Faster Whisper transcription via Jigasi and Skynet.
- Updated .env.example to include new environment variables for transcription settings.
- Enhanced Jitsi Docker Compose configuration to include Skynet and Jigasi services.
- Introduced new API endpoints for managing organizational folders in the drive service.
- Updated Nextcloud initialization script to enable external file mounting.
- Improved error handling and response structures in the drive API.
- Added new properties for organization settings related to transcription and agenda management.
2026-06-12 19:10:18 +02:00

120 lines
2.4 KiB
Go

package meet
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"time"
)
type Config struct {
AppID string
AppSecret string
Domain string
}
type RoomToken struct {
Token string `json:"token"`
Room string `json:"room"`
Domain string `json:"domain"`
MeetURL string `json:"meet_url"`
}
type UserInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Avatar string `json:"avatar,omitempty"`
IsMod bool `json:"is_moderator"`
}
// TokenOptions toggles JWT feature flags for Jitsi.
type TokenOptions struct {
Transcription bool
}
func NewConfig(appID, appSecret, domain string) *Config {
return &Config{
AppID: appID,
AppSecret: appSecret,
Domain: domain,
}
}
func (c *Config) GenerateToken(room string, user *UserInfo, ttl time.Duration, opts TokenOptions) (*RoomToken, error) {
now := time.Now()
exp := now.Add(ttl)
header := map[string]string{
"alg": "HS256",
"typ": "JWT",
}
userCtx := map[string]any{
"id": user.ID,
"name": user.Name,
"email": user.Email,
"avatar": user.Avatar,
"moderator": user.IsMod,
}
contextPayload := map[string]any{
"user": userCtx,
}
if opts.Transcription {
contextPayload["features"] = map[string]any{
"transcription": "true",
"recording": "false",
"livestreaming": "false",
}
}
payload := map[string]any{
"iss": c.AppID,
"sub": "meet.jitsi",
"aud": "ulti",
"iat": now.Unix(),
"exp": exp.Unix(),
"room": room,
"context": contextPayload,
}
token, err := signJWT(header, payload, c.AppSecret)
if err != nil {
return nil, err
}
return &RoomToken{
Token: token,
Room: room,
Domain: "meet.jitsi",
MeetURL: fmt.Sprintf("https://%s/meet/%s?jwt=%s", c.Domain, room, token),
}, nil
}
func signJWT(header map[string]string, payload map[string]any, secret string) (string, error) {
headerJSON, err := json.Marshal(header)
if err != nil {
return "", err
}
payloadJSON, err := json.Marshal(payload)
if err != nil {
return "", err
}
headerB64 := base64URLEncode(headerJSON)
payloadB64 := base64URLEncode(payloadJSON)
signingInput := headerB64 + "." + payloadB64
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(signingInput))
signature := base64URLEncode(mac.Sum(nil))
return signingInput + "." + signature, nil
}
func base64URLEncode(data []byte) string {
return base64.RawURLEncoding.EncodeToString(data)
}