84 lines
2.9 KiB
Go
84 lines
2.9 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
authpkg "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/auth"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
|
|
)
|
|
|
|
// resolveAccessTokenFromDir loads OAuth then legacy token from configDir, applying
|
|
// the same host compatibility hooks as MCP. It mirrors the former body of
|
|
// getCachedRuntimeToken (excluding process-level cache and timing).
|
|
func resolveAccessTokenFromDir(ctx context.Context, configDir string) (string, error) {
|
|
disc := slog.New(slog.NewTextHandler(io.Discard, nil))
|
|
provider := authpkg.NewOAuthProvider(configDir, disc)
|
|
configureOAuthProviderCompatibility(provider, configDir)
|
|
token, tokenErr := provider.GetAccessToken(ctx)
|
|
if tokenErr == nil && strings.TrimSpace(token) != "" {
|
|
return strings.TrimSpace(token), nil
|
|
}
|
|
if tokenErr != nil && errors.Is(tokenErr, authpkg.ErrTokenDecryption) {
|
|
return "", tokenErr
|
|
}
|
|
manager := authpkg.NewManager(configDir, nil)
|
|
configureLegacyAuthManagerCompatibility(manager)
|
|
if leg, _, err := manager.GetToken(); err == nil && strings.TrimSpace(leg) != "" {
|
|
return strings.TrimSpace(leg), nil
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
// ResolveAuxiliaryAccessToken resolves a bearer token for HTTP clients that should
|
|
// align with MCP tool calls. Non-empty explicitToken wins. When configDir matches
|
|
// the active edition config directory, the same process-cached path as MCP is used.
|
|
// Otherwise tokens are loaded from configDir with host compatibility hooks applied.
|
|
func ResolveAuxiliaryAccessToken(ctx context.Context, configDir, explicitToken string) (string, error) {
|
|
if t := strings.TrimSpace(explicitToken); t != "" {
|
|
return t, nil
|
|
}
|
|
if strings.TrimSpace(configDir) == "" {
|
|
return "", fmt.Errorf("config directory is empty")
|
|
}
|
|
if filepath.Clean(configDir) == filepath.Clean(defaultConfigDir()) {
|
|
if tok := resolveRuntimeAuthToken(ctx, ""); tok != "" {
|
|
return tok, nil
|
|
}
|
|
return "", noCredentialsError()
|
|
}
|
|
tok, err := resolveAccessTokenFromDir(ctx, configDir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if tok != "" {
|
|
return tok, nil
|
|
}
|
|
return "", noCredentialsError()
|
|
}
|
|
|
|
func noCredentialsError() error {
|
|
if edition.Get().IsEmbedded {
|
|
return fmt.Errorf("认证信息已失效,请重新认证")
|
|
}
|
|
return fmt.Errorf("no credentials found, run: dws auth login")
|
|
}
|