Implement per-project webhook secret

This commit is contained in:
simon987 2019-02-24 15:30:38 -05:00
parent c736cc3d98
commit 397805f915
22 changed files with 378 additions and 59 deletions

View File

@ -16,13 +16,6 @@ import (
func (api *WebAPI) ReceiveGitWebHook(r *Request) {
if !signatureValid(r) {
logrus.Error("WebHook signature does not match!")
r.Ctx.SetStatusCode(403)
_, _ = fmt.Fprintf(r.Ctx, "Signature does not match")
return
}
payload := &GitPayload{}
err := json.Unmarshal(r.Ctx.Request.Body(), payload)
if err != nil {
@ -35,11 +28,27 @@ func (api *WebAPI) ReceiveGitWebHook(r *Request) {
}).Info("Received git WebHook")
if !isProductionBranch(payload) {
r.Ctx.SetStatusCode(400)
return
}
project := api.getAssociatedProject(payload)
if project == nil {
r.Ctx.SetStatusCode(400)
return
}
signature, err := api.Database.GetWebhookSecret(project.Id)
if err != nil {
_, _ = fmt.Fprintf(r.Ctx, err.Error())
r.Ctx.SetStatusCode(400)
return
}
if !signatureValid(r, signature) {
logrus.Error("WebHook signature does not match!")
r.Ctx.SetStatusCode(403)
_, _ = fmt.Fprintf(r.Ctx, "Signature does not match")
return
}
@ -50,7 +59,7 @@ func (api *WebAPI) ReceiveGitWebHook(r *Request) {
handleErr(err, r)
}
func signatureValid(r *Request) (matches bool) {
func signatureValid(r *Request, webhookSignature string) (matches bool) {
signature := parseSignatureFromRequest(r.Ctx)
@ -60,7 +69,7 @@ func signatureValid(r *Request) (matches bool) {
body := r.Ctx.PostBody()
mac := hmac.New(getHashFuncFromConfig(), config.Cfg.WebHookSecret)
mac := hmac.New(getHashFuncFromConfig(), []byte(webhookSignature))
mac.Write(body)
expectedMac := hex.EncodeToString(mac.Sum(nil))

View File

@ -93,6 +93,8 @@ func New() *WebAPI {
api.router.POST("/project/reject_request/:id/:wid", LogRequestMiddleware(api.RejectAccessRequest))
api.router.GET("/project/secret/:id", LogRequestMiddleware(api.GetSecret))
api.router.POST("/project/secret/:id", LogRequestMiddleware(api.SetSecret))
api.router.GET("/project/webhook_secret/:id", LogRequestMiddleware(api.GetWebhookSecret))
api.router.POST("/project/webhook_secret/:id", LogRequestMiddleware(api.SetWebhookSecret))
api.router.POST("/task/submit", LogRequestMiddleware(api.SubmitTask))
api.router.GET("/task/get/:project", LogRequestMiddleware(api.GetTaskFromProject))

View File

@ -292,3 +292,10 @@ type SetSecretRequest struct {
type GetSecretResponse struct {
Secret string `json:"secret"`
}
type SetWebhookSecretRequest struct {
WebhookSecret string `json:"webhook_secret"`
}
type GetWebhookSecretResponse struct {
WebhookSecret string `json:"webhook_secret"`
}

View File

@ -3,6 +3,7 @@ package api
import (
"encoding/json"
"github.com/Sirupsen/logrus"
"github.com/google/uuid"
"github.com/simon987/task_tracker/storage"
"strconv"
)
@ -97,7 +98,9 @@ func (api *WebAPI) CreateProject(r *Request) {
return
}
id, err := api.Database.SaveProject(project)
webhookSecret := makeWebhookSecret()
id, err := api.Database.SaveProject(project, webhookSecret)
if err != nil {
r.Json(JsonResponse{
Ok: false,
@ -107,7 +110,7 @@ func (api *WebAPI) CreateProject(r *Request) {
}
api.Database.SetManagerRoleOn(manager.(*storage.Manager).Id, id,
storage.ROLE_MANAGE_ACCESS|storage.ROLE_READ|storage.ROLE_EDIT)
storage.RoleManageAccess|storage.RoleRead|storage.RoleEdit|storage.RoleSecret)
r.OkJson(JsonResponse{
Ok: true,
Content: CreateProjectResponse{
@ -119,6 +122,10 @@ func (api *WebAPI) CreateProject(r *Request) {
}).Debug("Created project")
}
func makeWebhookSecret() string {
return uuid.New().String()
}
func (api *WebAPI) UpdateProject(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
@ -163,7 +170,7 @@ func (api *WebAPI) UpdateProject(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(project.Id, manager, storage.ROLE_EDIT, api.Database) {
if !isActionOnProjectAuthorized(project.Id, manager, storage.RoleEdit, api.Database) {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
@ -238,7 +245,7 @@ func isProjectReadAuthorized(project *storage.Project, manager interface{}, db *
return true
}
role := db.GetManagerRoleOn(manager.(*storage.Manager), project.Id)
if role&storage.ROLE_READ == 1 {
if role&storage.RoleRead == 1 {
return true
}
@ -302,7 +309,7 @@ func (api *WebAPI) GetWorkerAccessListForProject(r *Request) {
return
}
if !isActionOnProjectAuthorized(id, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
if !isActionOnProjectAuthorized(id, manager, storage.RoleManageAccess, api.Database) {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
@ -391,7 +398,7 @@ func (api *WebAPI) AcceptAccessRequest(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
if !isActionOnProjectAuthorized(pid, manager, storage.RoleManageAccess, api.Database) {
r.Json(JsonResponse{
Message: "Unauthorized",
Ok: false,
@ -471,7 +478,7 @@ func (api *WebAPI) SetManagerRoleOnProject(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
if !isActionOnProjectAuthorized(pid, manager, storage.RoleManageAccess, api.Database) {
r.Json(JsonResponse{
Message: "Unauthorized",
Ok: false,
@ -500,7 +507,7 @@ func (api *WebAPI) SetSecret(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_EDIT, api.Database) {
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
@ -560,7 +567,7 @@ func (api *WebAPI) GetSecret(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_EDIT, api.Database) {
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
@ -576,3 +583,79 @@ func (api *WebAPI) GetSecret(r *Request) {
},
})
}
func (api *WebAPI) GetWebhookSecret(r *Request) {
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
if err != nil || pid <= 0 {
r.Json(JsonResponse{
Ok: false,
Message: "Invalid project id",
}, 400)
return
}
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
}, 403)
return
}
secret, err := api.Database.GetWebhookSecret(pid)
r.OkJson(JsonResponse{
Ok: true,
Content: GetWebhookSecretResponse{
WebhookSecret: secret,
},
})
}
func (api *WebAPI) SetWebhookSecret(r *Request) {
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
if err != nil || pid <= 0 {
r.Json(JsonResponse{
Ok: false,
Message: "Invalid project id",
}, 400)
return
}
req := &SetWebhookSecretRequest{}
err = json.Unmarshal(r.Ctx.Request.Body(), req)
if err != nil {
r.Json(JsonResponse{
Ok: false,
Message: "Could not parse request",
}, 400)
return
}
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionOnProjectAuthorized(pid, manager, storage.RoleSecret, api.Database) {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
}, 403)
return
}
err = api.Database.SetWebhookSecret(pid, req.WebhookSecret)
if err == nil {
r.OkJson(JsonResponse{
Ok: true,
})
} else {
r.OkJson(JsonResponse{
Ok: false,
Message: err.Error(),
})
}
}

View File

@ -7,7 +7,6 @@ database:
log_levels: ["error", "info", "warn"]
git:
webhook_secret: "very_secret_secret"
# Github: sha1, Gogs: sha256
webhook_hash: "sha256"
# Github: 'X-Hub-Signature', Gogs: 'X-Gogs-Signature'

View File

@ -11,10 +11,11 @@ import (
type ManagerRole int
const (
ROLE_NONE ManagerRole = 0
ROLE_READ ManagerRole = 1
ROLE_EDIT ManagerRole = 2
ROLE_MANAGE_ACCESS ManagerRole = 4
RoleNone ManagerRole = 0
RoleRead ManagerRole = 1
RoleEdit ManagerRole = 2
RoleManageAccess ManagerRole = 4
RoleSecret ManagerRole = 8
)
type Manager struct {
@ -142,7 +143,7 @@ func (database *Database) GetManagerRoleOn(manager *Manager, projectId int64) Ma
var role ManagerRole
err := row.Scan(&role)
if err != nil {
return ROLE_NONE
return RoleNone
}
return role

View File

@ -25,14 +25,14 @@ type AssignedTasks struct {
TaskCount int64 `json:"task_count"`
}
func (database *Database) SaveProject(project *Project) (int64, error) {
func (database *Database) SaveProject(project *Project, webhookSecret string) (int64, error) {
db := database.getDB()
row := db.QueryRow(`INSERT INTO project (name, git_repo, clone_url, version, priority,
motd, public, hidden, chain, paused)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0),$10) RETURNING id`,
motd, public, hidden, chain, paused, webhook_secret)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0),$10,$11) RETURNING id`,
project.Name, project.GitRepo, project.CloneUrl, project.Version, project.Priority, project.Motd,
project.Public, project.Hidden, project.Chain, project.Paused)
project.Public, project.Hidden, project.Chain, project.Paused, webhookSecret)
var id int64
err := row.Scan(&id)
@ -225,3 +225,23 @@ func (database *Database) SetSecret(pid int64, secret string) {
"project": pid,
}).Info("Set secret")
}
func (database *Database) GetWebhookSecret(pid int64) (secret string, err error) {
db := database.getDB()
row := db.QueryRow(`SELECT webhook_secret FROM project WHERE id=$1`, pid)
err = row.Scan(&secret)
return
}
func (database *Database) SetWebhookSecret(pid int64, secret string) (err error) {
db := database.getDB()
res, err := db.Exec(`UPDATE project SET webhook_secret=$1 WHERE id=$2`, secret, pid)
handleErr(err)
rowsAffected, _ := res.RowsAffected()
logrus.WithFields(logrus.Fields{
"project": pid,
"rowsAffected": rowsAffected,
}).Trace("Update webhook secret")
return
}

View File

@ -3,6 +3,7 @@ package test
import (
"bytes"
"encoding/json"
"fmt"
"github.com/simon987/task_tracker/api"
"github.com/simon987/task_tracker/config"
"golang.org/x/net/publicsuffix"
@ -177,3 +178,15 @@ func getSessionCtx(username string, password string, admin bool) *http.Client {
return client
}
func setRoleOnProject(req api.SetManagerRoleOnProjectRequest, pid int64, s *http.Client) (ar api.JsonResponse) {
r := Post(fmt.Sprintf("/manager/set_role_for_project/%d", pid), req, nil, s)
UnmarshalResponse(r, &ar)
return
}
func getAccountDetails(s *http.Client) (ar AccountAR) {
r := Get("/account", nil, s)
UnmarshalResponse(r, &ar)
return
}

View File

@ -15,7 +15,7 @@ func TestWebHookNoSignature(t *testing.T) {
r := Post("/git/receivehook", api.GitPayload{}, nil, nil)
if r.StatusCode != 403 {
if r.StatusCode == 200 {
t.Error()
}
}
@ -28,7 +28,7 @@ func TestWebHookInvalidSignature(t *testing.T) {
client := http.Client{}
r, _ := client.Do(req)
if r.StatusCode != 403 {
if r.StatusCode == 200 {
t.Error()
}
}
@ -41,10 +41,12 @@ func TestWebHookDontUpdateVersion(t *testing.T) {
GitRepo: "username/not_this_one",
}).Content
webhookSecret := getWebhookSecret(resp.Id, testAdminCtx).Content.WebhookSecret
body := []byte(`{"ref": "refs/heads/master", "after": "new", "repository": {"full_name": "username/repo_name"}}`)
bodyReader := bytes.NewReader(body)
mac := hmac.New(crypto.SHA1.New, config.Cfg.WebHookSecret)
mac := hmac.New(crypto.SHA1.New, []byte(webhookSecret))
mac.Write(body)
signature := hex.EncodeToString(mac.Sum(nil))
signature = "sha1=" + signature
@ -53,11 +55,7 @@ func TestWebHookDontUpdateVersion(t *testing.T) {
req.Header.Add("X-Hub-Signature", signature)
client := http.Client{}
r, _ := client.Do(req)
if r.StatusCode != 200 {
t.Error()
}
_, _ = client.Do(req)
getResp := getProjectAsAdmin(resp.Id).Content
@ -76,7 +74,9 @@ func TestWebHookUpdateVersion(t *testing.T) {
body := []byte(`{"ref": "refs/heads/master", "after": "new", "repository": {"full_name": "username/repo_name"}}`)
bodyReader := bytes.NewReader(body)
mac := hmac.New(crypto.SHA1.New, config.Cfg.WebHookSecret)
webhookSecret := getWebhookSecret(resp.Id, testAdminCtx).Content.WebhookSecret
mac := hmac.New(crypto.SHA1.New, []byte(webhookSecret))
mac.Write(body)
signature := hex.EncodeToString(mac.Sum(nil))
signature = "sha1=" + signature

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/simon987/task_tracker/api"
"github.com/simon987/task_tracker/storage"
"io/ioutil"
"net/http"
"testing"
@ -465,6 +466,82 @@ func TestPausedProjectShouldNotDispatchTasks(t *testing.T) {
}, testProject, testAdminCtx)
}
func TestGetWebhookSecret(t *testing.T) {
resp := getWebhookSecret(testProject, testAdminCtx)
if resp.Ok != true {
t.Error()
}
if len(resp.Content.WebhookSecret) <= 0 {
t.Error()
}
}
func TestSetWebhookSecret(t *testing.T) {
resp1 := setWebhookSecret(api.SetWebhookSecretRequest{
WebhookSecret: "new",
}, testProject, testAdminCtx)
if resp1.Ok != true {
t.Error()
}
resp := getWebhookSecret(testProject, testAdminCtx)
if resp.Ok != true {
t.Error()
}
if resp.Content.WebhookSecret != "new" {
t.Error()
}
}
func TestGetWebhookRequiresRole(t *testing.T) {
otherUser := getSessionCtx("testwebhookrole", "testwebhookrole", false)
otherUserId := getAccountDetails(otherUser).Content.Id
user := getSessionCtx("testwebhookroleu", "testwebhookroleu", false)
userId := getAccountDetails(user).Content.Id
resp := setRoleOnProject(api.SetManagerRoleOnProjectRequest{
Role: storage.RoleEdit | storage.RoleManageAccess | storage.RoleRead,
Manager: otherUserId,
}, testProject, testAdminCtx)
if resp.Ok != true {
t.Fail()
}
resp = setRoleOnProject(api.SetManagerRoleOnProjectRequest{
Role: storage.RoleSecret,
Manager: userId,
}, testProject, testAdminCtx)
if resp.Ok != true {
t.Fail()
}
rUser := setWebhookSecret(api.SetWebhookSecretRequest{
WebhookSecret: "test",
}, testProject, user)
rOther := setWebhookSecret(api.SetWebhookSecretRequest{
WebhookSecret: "test",
}, testProject, otherUser)
rGuest := setWebhookSecret(api.SetWebhookSecretRequest{
WebhookSecret: "test",
}, testProject, nil)
if rUser.Ok != true {
t.Error()
}
if rOther.Ok != false {
t.Error()
}
if rGuest.Ok != false {
t.Error()
}
}
func createProjectAsAdmin(req api.CreateProjectRequest) CreateProjectAR {
return createProject(req, testAdminCtx)
}
@ -502,3 +579,15 @@ func getProjectList(s *http.Client) (ar ProjectListAR) {
UnmarshalResponse(r, &ar)
return
}
func getWebhookSecret(pid int64, s *http.Client) (ar WebhookSecretAR) {
r := Get(fmt.Sprintf("/project/webhook_secret/%d", pid), nil, s)
UnmarshalResponse(r, &ar)
return
}
func setWebhookSecret(req api.SetWebhookSecretRequest, pid int64, s *http.Client) (ar api.JsonResponse) {
r := Post(fmt.Sprintf("/project/webhook_secret/%d", pid), req, nil, s)
UnmarshalResponse(r, &ar)
return
}

View File

@ -172,3 +172,19 @@ type ReleaseAR struct {
Updated bool `json:"updated"`
} `json:"content"`
}
type WebhookSecretAR struct {
Ok bool `json:"ok"`
Message string `json:"message"`
Content struct {
WebhookSecret string `json:"webhook_secret"`
} `json:"content"`
}
type AccountAR struct {
Ok bool `json:"ok"`
Message string `json:"message"`
Content struct {
*storage.Manager `json:"manager"`
} `json:"content"`
}

View File

@ -6,7 +6,6 @@ database:
log_levels: ["debug", "error", "trace", "info", "warn"]
git:
webhook_secret: "very_secret_secret"
webhook_hash: "sha1"
webhook_sig_header: "X-Hub-Signature"

View File

@ -25,7 +25,8 @@ CREATE TABLE project
git_repo TEXT NOT NULL,
version TEXT NOT NULL,
motd TEXT NOT NULL,
secret TEXT NOT NULL DEFAULT '{}'
secret TEXT NOT NULL DEFAULT '{}',
webhook_secret TEXT NOT NULL
);
CREATE TABLE worker_access

View File

@ -106,4 +106,12 @@ export class ApiService {
return this.http.post(this.url + `/project/secret/${pid}`, {"secret": secret})
}
getWebhookSecret(pid: number) {
return this.http.get(this.url + `/project/webhook_secret/${pid}`,)
}
setWebhookSecret(pid: number, secret: string) {
return this.http.post(this.url + `/project/webhook_secret/${pid}`, {"webhook_secret": secret})
}
}

View File

@ -51,4 +51,16 @@ export class ManagerRoleOnProject {
this.role &= ~4
}
}
get secretRole(): boolean {
return (this.role & 8) != 0
}
set secretRole(role: boolean) {
if (role) {
this.role |= 8
} else {
this.role &= ~8
}
}
}

View File

@ -366,13 +366,14 @@ export class ProjectDashboardComponent implements OnInit {
this.dialog.open(AreYouSureComponent, {
width: '250px',
}).afterClosed().subscribe(result => {
if (result) {
this.project.paused = paused;
this.apiService.updateProject(this.project).subscribe(() => {
this.translate.get("messenger.acknowledged").subscribe(t =>
this.messenger.show(t))
})
}
this.project.paused = paused;
this.apiService.updateProject(this.project).subscribe(() => {
this.translate.get("messenger.acknowledged").subscribe(t =>
this.messenger.show(t))
}, error => {
this.translate.get("messenger.unauthorized").subscribe(t =>
this.messenger.show(t))
})
});
}

View File

@ -33,6 +33,7 @@
<button mat-raised-button color="primary"
*ngIf="authService.logged"
[routerLink]="'/project/' + project.id + '/secret'">
<mat-icon>security</mat-icon>
{{"project.secret" | translate}}</button>
</div>
</mat-expansion-panel>

View File

@ -55,6 +55,10 @@
(change)="onRoleChange(m)"
[disabled]="m.manager.id==auth.account.id"
>{{"perms.manage"|translate}}</mat-checkbox>
<mat-checkbox [(ngModel)]="m.secretRole"
(change)="onRoleChange(m)"
[disabled]="m.manager.id==auth.account.id"
>{{"perms.secret"|translate}}</mat-checkbox>
</mat-list-item>
</mat-list>
</mat-card-content>

View File

@ -1,22 +1,47 @@
<div class="container">
<mat-card>
<mat-card class="mat-elevation-z8">
<button mat-button [title]="'perms.refresh' | translate" style="float:right"
(click)="refresh()">
<mat-icon>refresh</mat-icon>
</button>
<mat-card-header>
<mat-card-title>{{"secret.title" | translate}}</mat-card-title>
<mat-card-subtitle>{{"secret.subtitle" | translate}}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<mat-form-field appearance="outline">
<mat-label>{{"secret.secret" | translate}}</mat-label>
<textarea matInput [(ngModel)]="secret"
[placeholder]="'secret.secret'|translate"
name="secret"></textarea>
</mat-form-field>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button color="primary"
(click)="onUpdate()">{{"secret.update" | translate}}
</button>
</mat-card-actions>
</mat-card>
<mat-form-field appearance="outline">
<mat-label>{{"secret.secret" | translate}}</mat-label>
<textarea matInput [(ngModel)]="secret"
[placeholder]="'secret.secret'|translate"
name="secret"></textarea>
</mat-form-field>
<mat-card style="margin-top: 2em" class="mat-elevation-z8">
<mat-card-header>
<mat-card-title>{{"secret.webhook_title" | translate}}</mat-card-title>
<mat-card-subtitle>{{"secret.webhook_subtitle" | translate}}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<mat-form-field appearance="outline">
<mat-label>{{"secret.webhook_secret" | translate}}</mat-label>
<textarea matInput [(ngModel)]="webhookSecret"
[placeholder]="'secret.webhook_secret'|translate"
name="webhook_secret"></textarea>
</mat-form-field>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button [routerLink]="'../'">Back</button>
<button mat-raised-button color="primary"
(click)="onUpdate()">{{"secret.update" | translate}}</button>
(click)="onWebhookUpdate()">{{"secret.update" | translate}}</button>
</mat-card-actions>
</mat-card>
</div>

View File

@ -13,6 +13,7 @@ import {MessengerService} from "../messenger.service";
export class ProjectSecretComponent implements OnInit {
secret: string;
webhookSecret: string;
projectId: number;
constructor(private auth: AuthService,
@ -26,6 +27,7 @@ export class ProjectSecretComponent implements OnInit {
this.route.params.subscribe(params => {
this.projectId = params["id"];
this.getSecret();
this.getWebhookSecret();
});
}
@ -37,10 +39,28 @@ export class ProjectSecretComponent implements OnInit {
})
}
getWebhookSecret() {
this.apiService.getWebhookSecret(this.projectId).subscribe(data => {
this.webhookSecret = data["content"]["webhook_secret"]
}, error => {
this.translate.get("messenger.unauthorized").subscribe(t => this.messenger.show(t))
})
}
onUpdate() {
this.apiService.setSecret(this.projectId, this.secret).subscribe(data => {
this.translate.get("secret.ok").subscribe(t => this.messenger.show(t))
})
}
onWebhookUpdate() {
this.apiService.setWebhookSecret(this.projectId, this.webhookSecret).subscribe(data => {
this.translate.get("secret.ok").subscribe(t => this.messenger.show(t))
})
}
refresh() {
this.getWebhookSecret();
this.getSecret();
}
}

View File

@ -8,7 +8,8 @@
"login": "Login",
"worker_dashboard": "Workers",
"account": "Account",
"manager_list": "Managers"
"manager_list": "Managers",
"back": "back"
},
"logs": {
"title": "Logs",
@ -119,6 +120,7 @@
"read": "Read",
"edit": "Edit",
"manage": "Manage permissions",
"secret": "Configure secrets",
"set": "Changes saved",
"workers": "Workers",
"no_workers": "No workers have explicit access to this project",
@ -152,6 +154,9 @@
"secret": {
"title": "Project secret",
"subtitle": "You can set project configuration here. It is only accessible by workers with ASSIGN access to this project",
"webhook_title": "Webhook secret",
"webhook_subtitle": "You need to supply this to Github/Gogs for delivery to work",
"webhook_secret": "Webhook secret",
"secret": "Secret",
"update": "Update",
"ok": "Updated"

View File

@ -8,7 +8,8 @@
"login": "Ouvrir un session",
"worker_dashboard": "Workers",
"account": "Compte",
"manager_list": "Managers"
"manager_list": "Managers",
"back": "Arrière"
},
"logs": {
"title": "Journaux",
@ -116,11 +117,11 @@
"read": "Lecture",
"edit": "Modification",
"manage": "Gestion des permissions",
"secret": "Gestion des secrets",
"set": "Changements enregistrés",
"workers": "Workers",
"no_workers": "Aucun Worker n'a explicitement accès à ce projet",
"managers": "Managers",
"secret": "Secret"
"managers": "Managers"
},
"messenger": {
"close": "Fermer",
@ -148,8 +149,11 @@
"alias": "Alias pertinent"
},
"secret": {
"title": "Secret",
"title": "Secret du projet",
"subtitle": "Vous pouvez définir la configuration du projet ici. Ce n'est accessible que par les Workers ayant accès au projet",
"webhook_title": "Secret (Webhook)",
"webhook_subtitle": "Vous devez le donner à Github/Gogs.",
"webhook_secret": "Secret (Webhook)",
"secret": "Secret",
"update": "Mettre à jour",
"ok": "Mis à jour"