mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-25 06:35:32 +00:00
feat: add option to send Basic Auth header with webhook requests (#2137)
Resolves https://github.com/go-vikunja/vikunja/issues/2136 Docs PR: https://github.com/go-vikunja/website/pull/284
This commit is contained in:
@@ -1328,4 +1328,4 @@
|
|||||||
"years": "Jahr|Jahre"
|
"years": "Jahr|Jahre"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1328,4 +1328,4 @@
|
|||||||
"years": "Jahr|Jahre"
|
"years": "Jahr|Jahre"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -439,6 +439,9 @@
|
|||||||
"deleteSuccess": "The webhook was successfully deleted.",
|
"deleteSuccess": "The webhook was successfully deleted.",
|
||||||
"create": "Create webhook",
|
"create": "Create webhook",
|
||||||
"secret": "Secret",
|
"secret": "Secret",
|
||||||
|
"basicauthuser": "Basic Auth User",
|
||||||
|
"basicauthpassword": "Basic Auth Password",
|
||||||
|
"basicauthlink": "Use Basic Auth?",
|
||||||
"secretHint": "If provided, all requests to the webhook target URL will be signed using HMAC.",
|
"secretHint": "If provided, all requests to the webhook target URL will be signed using HMAC.",
|
||||||
"secretDocs": "Check out the docs for more details about how to use secrets."
|
"secretDocs": "Check out the docs for more details about how to use secrets."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import type {IUser} from '@/modelTypes/IUser'
|
|||||||
export interface IWebhook extends IAbstract {
|
export interface IWebhook extends IAbstract {
|
||||||
id: number
|
id: number
|
||||||
projectId: number
|
projectId: number
|
||||||
secret: string
|
secret: string
|
||||||
|
basicauthuser: string
|
||||||
|
basicauthpassword: string
|
||||||
targetUrl: string
|
targetUrl: string
|
||||||
events: string[]
|
events: string[]
|
||||||
createdBy: IUser
|
createdBy: IUser
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ export default class WebhookModel extends AbstractModel<IWebhook> implements IWe
|
|||||||
id = 0
|
id = 0
|
||||||
projectId = 0
|
projectId = 0
|
||||||
secret = ''
|
secret = ''
|
||||||
|
basicauthuser = ''
|
||||||
|
basicauthpassword = ''
|
||||||
targetUrl = ''
|
targetUrl = ''
|
||||||
events = []
|
events = []
|
||||||
createdBy = null
|
createdBy = null
|
||||||
@@ -16,7 +18,7 @@ export default class WebhookModel extends AbstractModel<IWebhook> implements IWe
|
|||||||
constructor(data: Partial<IWebhook> = {}) {
|
constructor(data: Partial<IWebhook> = {}) {
|
||||||
super()
|
super()
|
||||||
this.assignData(data)
|
this.assignData(data)
|
||||||
|
|
||||||
this.createdBy = new UserModel(this.createdBy)
|
this.createdBy = new UserModel(this.createdBy)
|
||||||
|
|
||||||
this.created = new Date(this.created)
|
this.created = new Date(this.created)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import WebhookModel from '@/models/webhook'
|
|||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import FancyCheckbox from '@/components/input/FancyCheckbox.vue'
|
import FancyCheckbox from '@/components/input/FancyCheckbox.vue'
|
||||||
import FormField from '@/components/input/FormField.vue'
|
import FormField from '@/components/input/FormField.vue'
|
||||||
|
import Expandable from '@/components/base/Expandable.vue'
|
||||||
import {success} from '@/message'
|
import {success} from '@/message'
|
||||||
import {isValidHttpUrl} from '@/helpers/isValidHttpUrl'
|
import {isValidHttpUrl} from '@/helpers/isValidHttpUrl'
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ const project = ref<IProject>()
|
|||||||
useTitle(t('project.webhooks.title'))
|
useTitle(t('project.webhooks.title'))
|
||||||
|
|
||||||
const showNewForm = ref(false)
|
const showNewForm = ref(false)
|
||||||
|
const showBasicAuth = ref(false)
|
||||||
|
|
||||||
async function loadProject(projectId: number) {
|
async function loadProject(projectId: number) {
|
||||||
const projectService = new ProjectService()
|
const projectService = new ProjectService()
|
||||||
@@ -167,6 +169,47 @@ function validateSelectedEvents() {
|
|||||||
</BaseButton>
|
</BaseButton>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<BaseButton
|
||||||
|
class="mbe-2 has-text-primary"
|
||||||
|
@click="showBasicAuth = !showBasicAuth"
|
||||||
|
>
|
||||||
|
{{ $t('project.webhooks.basicauthlink') }}
|
||||||
|
</BaseButton>
|
||||||
|
<Expandable
|
||||||
|
:open="showBasicAuth"
|
||||||
|
class="content"
|
||||||
|
>
|
||||||
|
<div class="field">
|
||||||
|
<label
|
||||||
|
class="label"
|
||||||
|
for="basicauthuser"
|
||||||
|
>
|
||||||
|
{{ $t('project.webhooks.basicauthuser') }}
|
||||||
|
</label>
|
||||||
|
<div class="control">
|
||||||
|
<input
|
||||||
|
id="basicauthuser"
|
||||||
|
v-model="newWebhook.basicauthuser"
|
||||||
|
class="input"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label
|
||||||
|
class="label"
|
||||||
|
for="basicauthpassword"
|
||||||
|
>
|
||||||
|
{{ $t('project.webhooks.basicauthpassword') }}
|
||||||
|
</label>
|
||||||
|
<div class="control">
|
||||||
|
<input
|
||||||
|
id="basicauthpassword"
|
||||||
|
v-model="newWebhook.basicauthpassword"
|
||||||
|
class="input"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Expandable>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label
|
<label
|
||||||
class="label"
|
class="label"
|
||||||
|
|||||||
44
pkg/migration/20260123000717.go
Normal file
44
pkg/migration/20260123000717.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Vikunja is a to-do list application to facilitate your life.
|
||||||
|
// Copyright 2018-present Vikunja and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package migration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"src.techknowlogick.com/xormigrate"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type webhooks20260123000717 struct {
|
||||||
|
BasicAuthUser string `xorm:"null" json:"basicauthuser"`
|
||||||
|
BasicAuthPassword string `xorm:"null" json:"basicauthpassword"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (webhooks20260123000717) TableName() string {
|
||||||
|
return "webhooks"
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
migrations = append(migrations, &xormigrate.Migration{
|
||||||
|
ID: "20260123000717",
|
||||||
|
Description: "Add basic auth to webhooks",
|
||||||
|
Migrate: func(tx *xorm.Engine) error {
|
||||||
|
return tx.Sync(webhooks20260123000717{})
|
||||||
|
},
|
||||||
|
Rollback: func(tx *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -55,6 +55,9 @@ type Webhook struct {
|
|||||||
ProjectID int64 `xorm:"bigint not null index" json:"project_id" param:"project"`
|
ProjectID int64 `xorm:"bigint not null index" json:"project_id" param:"project"`
|
||||||
// If provided, webhook requests will be signed using HMAC. Check out the docs about how to use this: https://vikunja.io/docs/webhooks/#signing
|
// If provided, webhook requests will be signed using HMAC. Check out the docs about how to use this: https://vikunja.io/docs/webhooks/#signing
|
||||||
Secret string `xorm:"null" json:"secret"`
|
Secret string `xorm:"null" json:"secret"`
|
||||||
|
// If provided, webhook requests will be sent with a Basic Auth header.
|
||||||
|
BasicAuthUser string `xorm:"null" json:"basic_auth_user"`
|
||||||
|
BasicAuthPassword string `xorm:"null" json:"basic_auth_password"`
|
||||||
|
|
||||||
// The user who initially created the webhook target.
|
// The user who initially created the webhook target.
|
||||||
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
||||||
@@ -289,6 +292,10 @@ func (w *Webhook) sendWebhookPayload(p *WebhookPayload) (err error) {
|
|||||||
req.Header.Add("X-Vikunja-Signature", signature)
|
req.Header.Add("X-Vikunja-Signature", signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(w.BasicAuthUser) > 0 && len(w.BasicAuthPassword) > 0 {
|
||||||
|
req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(w.BasicAuthUser+":"+w.BasicAuthPassword)))
|
||||||
|
}
|
||||||
|
|
||||||
req.Header.Add("User-Agent", "Vikunja/"+version.Version)
|
req.Header.Add("User-Agent", "Vikunja/"+version.Version)
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
|||||||
@@ -9782,4 +9782,4 @@
|
|||||||
"in": "header"
|
"in": "header"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user