fix error code checking to not just check the raw string response in the case that '401' shows up in the sha256

This commit is contained in:
Evan Jarrett
2026-02-27 19:51:39 -06:00
parent 136c0a0ecc
commit 7c064ba8b0
3 changed files with 52 additions and 11 deletions
+2 -1
View File
@@ -17,7 +17,8 @@ done
# System packages
export DEBIAN_FRONTEND=noninteractive
apt-get update && apt-get upgrade -y
apt-get install -y git gcc make curl libsqlite3-dev nodejs npm htop
apt-get install -y git gcc make curl libsqlite3-dev nodejs npm htop systemd-timesyncd
timedatectl set-ntp true
# Swap (for small instances)
if [ ! -f /swapfile ]; then
+25 -6
View File
@@ -2,27 +2,46 @@ package handlers
import (
"context"
"errors"
"log/slog"
"strings"
"atcr.io/pkg/auth/oauth"
"github.com/bluesky-social/indigo/atproto/atclient"
"github.com/bluesky-social/indigo/xrpc"
)
// isOAuthError checks if an error indicates OAuth authentication failure
// These errors indicate the OAuth session is invalid and should be cleaned up
// Uses structured error types to avoid false positives from substring matching
func isOAuthError(err error) bool {
if err == nil {
return false
}
// Check structured error types first
var xrpcErr *xrpc.Error
if errors.As(err, &xrpcErr) && (xrpcErr.StatusCode == 401 || xrpcErr.StatusCode == 403) {
return true
}
var apiErr *atclient.APIError
if errors.As(err, &apiErr) {
if apiErr.StatusCode == 401 || apiErr.StatusCode == 403 {
return true
}
if apiErr.Name == "InvalidToken" || apiErr.Name == "InsufficientScope" || apiErr.Name == "InvalidGrant" {
return true
}
}
// Fallback: check for known auth-specific error strings that won't
// appear in digests or URIs
errStr := strings.ToLower(err.Error())
return strings.Contains(errStr, "401") ||
strings.Contains(errStr, "403") ||
strings.Contains(errStr, "invalid_token") ||
return strings.Contains(errStr, "invalid_token") ||
strings.Contains(errStr, "invalid_grant") ||
strings.Contains(errStr, "use_dpop_nonce") ||
strings.Contains(errStr, "unauthorized") ||
strings.Contains(errStr, "token") && strings.Contains(errStr, "expired") ||
strings.Contains(errStr, "authentication failed")
strings.Contains(errStr, "authentication failed") ||
strings.Contains(errStr, "token expired")
}
// handleOAuthError checks if an error is OAuth-related and invalidates UI sessions if so
+25 -4
View File
@@ -6,6 +6,7 @@ package oauth
import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
@@ -13,9 +14,11 @@ import (
"time"
"atcr.io/pkg/atproto"
"github.com/bluesky-social/indigo/atproto/atclient"
"github.com/bluesky-social/indigo/atproto/atcrypto"
"github.com/bluesky-social/indigo/atproto/auth/oauth"
"github.com/bluesky-social/indigo/atproto/syntax"
"github.com/bluesky-social/indigo/xrpc"
)
// permissionSetExpansions maps lexicon IDs to their expanded scope format.
@@ -312,16 +315,34 @@ func (r *Refresher) DoWithSession(ctx context.Context, did string, fn func(sessi
}
// isAuthError checks if an error looks like an OAuth/auth failure
// Uses structured error types to avoid false positives from substring matching
// (e.g., a digest hash containing "401" in a RecordNotFound error)
func isAuthError(err error) bool {
if err == nil {
return false
}
// Check structured error types first
var xrpcErr *xrpc.Error
if errors.As(err, &xrpcErr) && xrpcErr.StatusCode == 401 {
return true
}
var apiErr *atclient.APIError
if errors.As(err, &apiErr) {
if apiErr.StatusCode == 401 {
return true
}
if apiErr.Name == "InvalidToken" || apiErr.Name == "InsufficientScope" {
return true
}
}
// Fallback: check for known auth-specific error strings that won't
// appear in digests or URIs
errStr := strings.ToLower(err.Error())
return strings.Contains(errStr, "unauthorized") ||
strings.Contains(errStr, "invalid_token") ||
return strings.Contains(errStr, "invalid_token") ||
strings.Contains(errStr, "insufficient_scope") ||
strings.Contains(errStr, "token expired") ||
strings.Contains(errStr, "401")
strings.Contains(errStr, "token expired")
}
// resumeSession loads a session from storage