fix: Various oauth issues

This commit is contained in:
jamesread 2025-11-22 22:39:05 +00:00
parent d05ea54f8d
commit 3d763a84df
9 changed files with 53 additions and 51 deletions

View File

@ -1,4 +1,4 @@
// @generated by protoc-gen-es v2.10.0 // @generated by protoc-gen-es v2.10.1
// @generated from file olivetin/api/v1/olivetin.proto (package olivetin.api.v1, syntax proto3) // @generated from file olivetin/api/v1/olivetin.proto (package olivetin.api.v1, syntax proto3)
/* eslint-disable */ /* eslint-disable */
@ -1421,15 +1421,15 @@ export declare type OAuth2Provider = Message<"olivetin.api.v1.OAuth2Provider"> &
*/ */
title: string; title: string;
/**
* @generated from field: string url = 2;
*/
url: string;
/** /**
* @generated from field: string icon = 3; * @generated from field: string icon = 3;
*/ */
icon: string; icon: string;
/**
* @generated from field: string key = 4;
*/
key: string;
}; };
/** /**

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
<div v-if="hasOAuth" class="login-oauth2"> <div v-if="hasOAuth" class="login-oauth2">
<h3>OAuth Login</h3> <h3>OAuth Login</h3>
<div class="oauth-providers"> <div class="oauth-providers">
<button v-for="provider in oauthProviders" :key="provider.name || provider.title" class="oauth-button" <button v-for="provider in oauthProviders" :key="provider.key" class="oauth-button"
@click="loginWithOAuth(provider)"> @click="loginWithOAuth(provider)">
<span v-if="provider.icon" class="provider-icon" v-html="provider.icon"></span> <span v-if="provider.icon" class="provider-icon" v-html="provider.icon"></span>
<span class="provider-name">Login with {{ provider.title }}</span> <span class="provider-name">Login with {{ provider.title }}</span>
@ -106,9 +106,13 @@ async function handleLocalLogin() {
} }
function loginWithOAuth(provider) { function loginWithOAuth(provider) {
const providerName = provider.title.toLowerCase() if (!provider.key) {
console.error('OAuth provider missing key:', provider)
return
}
window.location.href = `/oauth/login?provider=${providerName}` const providerKey = encodeURIComponent(provider.key)
window.location.href = `/oauth/login?provider=${providerKey}`
} }
onMounted(() => { onMounted(() => {
@ -138,4 +142,12 @@ form {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 1em; gap: 1em;
} }
.provider-icon {
width: 1em;
height: 1em;
margin-right: .4em;
display: inline-flex;
vertical-align: middle;
}
</style> </style>

View File

@ -11,7 +11,8 @@ checkForUpdates: false
authOAuth2RedirectUrl: "http://localhost:1337/oauth2/callback" authOAuth2RedirectUrl: "http://localhost:1337/oauth2/callback"
authOAuth2Providers: authOAuth2Providers:
github: github:
title: "GitHub" name: github
title: "Good old GitHub"
clientId: "test-client-id" clientId: "test-client-id"
clientSecret: "test-client-secret" clientSecret: "test-client-secret"
@ -21,7 +22,7 @@ authRequireGuestsToLogin: true
# Simple actions for testing # Simple actions for testing
actions: actions:
- title: Ping Google.com - title: Ping Google.com
shell: ping google.com -c 1 shell: echo "ping google.com"
icon: ping icon: ping
- title: sleep 2 seconds - title: sleep 2 seconds

View File

@ -4,13 +4,13 @@ import { By, until, Condition } from 'selenium-webdriver'
import { import {
getRootAndWait, getRootAndWait,
takeScreenshotOnFailure, takeScreenshotOnFailure,
} from '../lib/elements.js' } from '../../lib/elements.js'
describe('config: githubOAuth', function () { describe('config: githubOAuth', function () {
this.timeout(30000) this.timeout(30000)
before(async function () { before(async function () {
await runner.start('githubOAuth') await runner.start('oauthLoginGithub')
}) })
after(async () => { after(async () => {
@ -75,37 +75,25 @@ describe('config: githubOAuth', function () {
await new Promise(resolve => setTimeout(resolve, 3000)) await new Promise(resolve => setTimeout(resolve, 3000))
// Find GitHub OAuth button // Find GitHub OAuth button
// Since the test config only has one provider (GitHub), we can use the first button
const githubButtons = await webdriver.findElements(By.css('.oauth-button')) const githubButtons = await webdriver.findElements(By.css('.oauth-button'))
expect(githubButtons.length).to.be.greaterThan(0) expect(githubButtons.length).to.be.greaterThan(0, 'At least one OAuth button should be present')
let githubButton = null const githubButton = githubButtons[0]
for (const button of githubButtons) { const buttonText = await githubButton.getText()
const buttonText = await button.getText() console.log('Button text:', buttonText)
if (buttonText.toLowerCase().includes('github')) {
githubButton = button
break
}
}
expect(githubButton).to.not.be.null('GitHub OAuth button should be present') // Verify it's the GitHub button (should contain "github" in the text)
expect(buttonText.toLowerCase()).to.include('github', 'Button should be GitHub OAuth button')
// Verify button is displayed and enabled
const isDisplayed = await githubButton.isDisplayed()
expect(isDisplayed).to.be.true('GitHub OAuth button should be displayed')
const isEnabled = await githubButton.isEnabled()
expect(isEnabled).to.be.true('GitHub OAuth button should be enabled')
// Check for provider icon (if present) // Check for provider icon (if present)
const providerIcons = await githubButton.findElements(By.css('.provider-icon')) const providerIcons = await githubButton.findElements(By.css('.provider-icon'))
// Icon may or may not be present, so we don't assert on it
// Check for provider name
const providerNames = await githubButton.findElements(By.css('.provider-name')) const providerNames = await githubButton.findElements(By.css('.provider-name'))
// Provider name may show "GitHub" (from title) or be undefined (if using name field) // Provider name may show "GitHub" (from title) or be undefined (if using name field)
// Just verify the structure is present // Just verify the structure is present
if (providerNames.length > 0) { if (providerNames.length > 0) {
const providerNameText = await providerNames[0].getText() const providerNameText = await providerNames[0].getText()
expect(providerNameText.toLowerCase()).to.include('github', 'Provider name should include "github"')
expect(providerNameText).to.include('Login with', 'Provider name should have "Login with" prefix') expect(providerNameText).to.include('Login with', 'Provider name should have "Login with" prefix')
console.log('Provider name text:', providerNameText) console.log('Provider name text:', providerNameText)
} }

View File

@ -329,8 +329,8 @@ message AdditionalLink {
message OAuth2Provider { message OAuth2Provider {
string title = 1; string title = 1;
string url = 2;
string icon = 3; string icon = 3;
string key = 4;
} }
message GetActionBindingRequest { message GetActionBindingRequest {

View File

@ -3390,8 +3390,8 @@ func (x *AdditionalLink) GetUrl() string {
type OAuth2Provider struct { type OAuth2Provider struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"` Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"`
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -3433,16 +3433,16 @@ func (x *OAuth2Provider) GetTitle() string {
return "" return ""
} }
func (x *OAuth2Provider) GetUrl() string { func (x *OAuth2Provider) GetIcon() string {
if x != nil { if x != nil {
return x.Url return x.Icon
} }
return "" return ""
} }
func (x *OAuth2Provider) GetIcon() string { func (x *OAuth2Provider) GetKey() string {
if x != nil { if x != nil {
return x.Icon return x.Key
} }
return "" return ""
} }
@ -4003,9 +4003,9 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\x05title\x18\x01 \x01(\tR\x05title\x12\x10\n" + "\x05title\x18\x01 \x01(\tR\x05title\x12\x10\n" +
"\x03url\x18\x02 \x01(\tR\x03url\"L\n" + "\x03url\x18\x02 \x01(\tR\x03url\"L\n" +
"\x0eOAuth2Provider\x12\x14\n" + "\x0eOAuth2Provider\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12\x10\n" + "\x05title\x18\x01 \x01(\tR\x05title\x12\x12\n" +
"\x03url\x18\x02 \x01(\tR\x03url\x12\x12\n" + "\x04icon\x18\x03 \x01(\tR\x04icon\x12\x10\n" +
"\x04icon\x18\x03 \x01(\tR\x04icon\"8\n" + "\x03key\x18\x04 \x01(\tR\x03key\"8\n" +
"\x17GetActionBindingRequest\x12\x1d\n" + "\x17GetActionBindingRequest\x12\x1d\n" +
"\n" + "\n" +
"binding_id\x18\x01 \x01(\tR\tbindingId\"K\n" + "binding_id\x18\x01 \x01(\tR\tbindingId\"K\n" +

View File

@ -865,11 +865,11 @@ func (api *oliveTinAPI) addCustomDashboards(rootDashboards *[]string, dashboards
func buildPublicOAuth2ProvidersList(cfg *config.Config) []*apiv1.OAuth2Provider { func buildPublicOAuth2ProvidersList(cfg *config.Config) []*apiv1.OAuth2Provider {
var publicProviders []*apiv1.OAuth2Provider var publicProviders []*apiv1.OAuth2Provider
for _, provider := range cfg.AuthOAuth2Providers { for providerKey, provider := range cfg.AuthOAuth2Providers {
publicProviders = append(publicProviders, &apiv1.OAuth2Provider{ publicProviders = append(publicProviders, &apiv1.OAuth2Provider{
Title: provider.Title, Title: provider.Title,
Url: provider.AuthUrl,
Icon: provider.Icon, Icon: provider.Icon,
Key: providerKey,
}) })
} }

View File

@ -8,13 +8,14 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
config "github.com/OliveTin/OliveTin/internal/config"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"io" "io"
"net/http" "net/http"
"os" "os"
"time" "time"
config "github.com/OliveTin/OliveTin/internal/config"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
) )
type OAuth2Handler struct { type OAuth2Handler struct {