As we reevaluate how to best support and maintain Staging Ref in the future, we encourage development teams using this environment to highlight their use cases in the following issue: https://gitlab.com/gitlab-com/gl-infra/software-delivery/framework/software-delivery-framework-issue-tracker/-/issues/36.

Skip to content
Snippets Groups Projects

Passing pushauth flag as bool in json body to internal api doesn't become a...

Open Manoj Memana Jayakumar requested to merge mmj/gitlab-shell:506-jsandlin into main
11 files
+ 1164
69
Compare changes
  • Side-by-side
  • Inline
Files
11
@@ -4,6 +4,8 @@ import (
"context"
"fmt"
"io"
"sync"
"time"
"gitlab.com/gitlab-org/labkit/log"
@@ -15,25 +17,162 @@ import (
type Command struct {
Config *config.Config
Client *twofactorverify.Client
Args *commandargs.Shell
ReadWriter *readwriter.ReadWriter
}
type Result struct {
Error error
Status string
Success bool
}
var (
mu sync.RWMutex
// TODO: make timeout configurable
ctxMaxTime = time.Second + 30
)
func (c *Command) Execute(ctx context.Context) error {
ctxlog := log.ContextLogger(ctx)
ctxlog.Info("twofactorverify: execute: waiting for user input")
otp := c.getOTP(ctx)
ctxlog.Info("twofactorverify: execute: verifying entered OTP")
err := c.verifyOTP(ctx, otp)
// config.GetHTTPClient isn't thread-safe so save Client in struct for concurrency
// workaround until #518 is fixed
var err error
c.Client, err = twofactorverify.NewClient(c.Config)
if err != nil {
ctxlog.WithError(err).Error("twofactorverify: execute: OTP verification failed")
return err
}
ctxlog.WithError(err).Info("twofactorverify: execute: OTP verified")
waitGroup := sync.WaitGroup{}
myctx, cancelCtx := context.WithTimeout(ctx, ctxMaxTime)
defer cancelCtx()
//myctx, mycancel := context.WithCancel(timeoutCtx)
myctx2, cancelCtx2 := context.WithTimeout(ctx, ctxMaxTime)
defer cancelCtx2()
// Also allow manual OTP entry while waiting for push, with same timeout as push
otpChannel := make(chan Result)
waitGroup.Add(1)
//defer close(otpChannel)
go func() {
defer waitGroup.Done()
ctxlog.Info("twofactorverify: execute: waiting for user input")
otpAnswer := c.getOTP(myctx)
select {
case <-ctx.Done(): // manual OTP cancelled by push
otpChannel <- Result{Error: nil, Status: "cancelled", Success: false}
default:
status, success, err := c.verifyOTP(myctx, otpAnswer)
otpChannel <- Result{Error: err, Status: status, Success: success}
}
//cancelCtx()
}()
//// Background push notification with timeout
pushChannel := make(chan Result)
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
//defer close(pushChannel)
ctxlog.Info("twofactorverify: execute: waiting for push auth")
ctxlog.WithError(err).Info("twofactorverify: execute: push auth verified")
select {
case <-myctx2.Done(): // push cancelled by manual OTP
// skip writing to channel
pushChannel <- Result{Error: nil, Status: "cancelled", Success: false}
ctxlog.Info("twofactorverify: execute: push auth cancelled")
default:
status, success, err := c.pushAuth(myctx2)
pushChannel <- Result{Error: err, Status: status, Success: success}
}
}()
select {
case res := <-otpChannel:
//fmt.Println("Received from otpChannel => ", res)
if len(res.Status) > 0 && res.Status != "cancelled" {
fmt.Fprint(c.ReadWriter.Out, res.Status)
return nil
}
case res := <-pushChannel:
if len(res.Status) > 0 && res.Status != "cancelled" {
//fmt.Println("Received from pushChannel => ", res)
fmt.Println("res.Status == ", res.Status, " -> ", len(res.Status))
fmt.Fprint(c.ReadWriter.Out, res.Status)
return nil
}
case <- myctx.Done():
fmt.Fprint(c.ReadWriter.Out, "\nOTP verification timed out\n")
return nil
}
waitGroup.Wait()
return nil
}
//
//func (c Command) processCmd(ctx context.Context, cancelTimeout context.CancelFunc) (result Result) {
// ctxlog := log.ContextLogger(ctx)
//
// otpAuth := make(chan Result)
// go func() {
// defer close(otpAuth)
// ctxlog.Info("twofactorverify: execute: waiting for user input")
// otpAnswer := c.getOTP(ctx)
//
// select {
// case <-ctx.Done(): // manual OTP cancelled by push
// fmt.Println("otpAuth.ctx.Done()")
// otpAuth <- Result{Error: nil, Status: "cancelled", Success: false}
// fmt.Println("----------------------------------------------------")
// fmt.Println("otpAuth = ", otpAuth)
// fmt.Println("----------------------------------------------------")
// default:
// fmt.Println("otpAuth.default")
// cancelTimeout()
// fmt.Println("Call c.verifyOTP(", ctx, ", ", otpAnswer, ")")
// status, success, err := c.verifyOTP(ctx, otpAnswer)
// fmt.Println("otpAnswer.status = ", status)
// fmt.Println("otpAnswer.success = ", success)
// fmt.Println("otpAnswer.err = ", err)
// otpAuth <- Result{Error: err, Status: status, Success: success}
// fmt.Println("----------------------------------------------------")
// fmt.Println("otpAuth = ", otpAuth)
// fmt.Println("----------------------------------------------------")
// }
// }()
// for {
// //fmt.Println("for loop")
// select {
// case res := <- otpAuth:
// fmt.Println(res)
// //fmt.Println("-------------")
// //fmt.Println("otpAuth = ", ores)
// //fmt.Println("-------------")
// if len(res.Status) > 0 && res.Status != "cancelled"{
// //fmt.Println("-------------")
// //fmt.Println("otpAuth = ", res.Status)
// //fmt.Println("-------------")
// return res
// }
// }
// }
// return
//}
//
//
func (c *Command) getOTP(ctx context.Context) string {
prompt := "OTP: "
@@ -49,18 +188,49 @@ func (c *Command) getOTP(ctx context.Context) string {
return answer
}
func (c *Command) verifyOTP(ctx context.Context, otp string) error {
client, err := twofactorverify.NewClient(c.Config)
if err != nil {
return err
func (c *Command) verifyOTP(ctx context.Context, otp string) (status string, success bool, err error) {
reason := ""
//fmt.Println("verifyOTP(", ctx, ", ", c.Args, ", ",otp,")")
success, reason, err = c.Client.VerifyOTP(ctx, c.Args, otp)
//fmt.Println("----------------------------------------------------")
//fmt.Println("verifyOTP.status = ", status)
//fmt.Println("verifyOTP.success = ", success)
//fmt.Println("verifyOTP.err = ", err)
//fmt.Println("----------------------------------------------------")
if success {
status = fmt.Sprintf("\nOTP validation successful. Git operations are now allowed.\n")
} else {
if err != nil {
status = fmt.Sprintf("\nOTP validation failed.\n%v\n", err)
} else {
status = fmt.Sprintf("\nOTP validation failed.\n%v\n", reason)
}
}
err = client.VerifyOTP(ctx, c.Args, otp)
if err == nil {
fmt.Fprint(c.ReadWriter.Out, "\nOTP validation successful. Git operations are now allowed.\n")
err = nil
return
}
func (c *Command) pushAuth(ctx context.Context) (status string, success bool, err error) {
//fmt.Println("---------------------------------------")
reason := ""
//fmt.Println(c.Args)
success, reason, err = c.Client.PushAuth(ctx, c.Args)
//fmt.Println("pushAuth.reason = ", reason)
//fmt.Println("pushAuth.success = ", success)
//fmt.Println("pushAuth.err = ", err)
//fmt.Println("---------------------------------------")
if success {
status = fmt.Sprintf("\nPush OTP validation successful. Git operations are now allowed.\n")
} else {
fmt.Fprintf(c.ReadWriter.Out, "\nOTP validation failed.\n%v\n", err)
if err != nil {
status = fmt.Sprintf("\nPush OTP validation failed.\n%v\n", err)
} else {
status = fmt.Sprintf("\nPush OTP validation failed.\n%v\n", reason)
}
}
return nil
return
}
Loading