Home > Back-end >  Can't get Golang library to return anything but nil to controller
Can't get Golang library to return anything but nil to controller

Time:12-17

Golang toddler here, so I'd imagine I'm missing something obvious. After experimenting for a couple of days though, I decided to reach out for some help. :-)

The code I'm posting is working, except for the situation when a user requests a new client certificate/key package be created (this is an OpenVPN server administrative WebUI), when a client of the same name already exists. And even in that case, no new client package is created, but an incorrect alert message is displayed indicating that it has been.

I know I need to rework the controller to display different alert banners, based on whether the name exists or not. However, I'm stuck on getting anything besides "nil" back from the library.

The Golang controller code is as follows:

    func (c *CertificatesController) Post() {
    c.TplName = "certificates.html"
    flash := beego.NewFlash()

    cParams := NewCertParams{}
    if err := c.ParseForm(&cParams); err != nil {
        beego.Error(err)
        flash.Error(err.Error())
        flash.Store(&c.Controller)
    } else {
        if vMap := validateCertParams(cParams); vMap != nil {
            c.Data["validation"] = vMap
        } else {
            if err := lib.CreateCertificate(cParams.Name, cParams.Passphrase); err != nil {
                beego.Error(err)
                flash.Error(err.Error())
                flash.Store(&c.Controller)
            } else {
                fmt.Println(err)
                flash.Success("Certificate for the name \""   cParams.Name   "\" created")
                flash.Store(&c.Controller)
            }
        }
    }
    c.showCerts()
}

And the library function that's called via lib.CreateCertificate:

    func CreateCertificate(name string, passphrase string) error {
    rsaPath := models.GlobalCfg.OVConfigPath   "easy-rsa"
    rsaIndex := models.GlobalCfg.OVConfigPath   "easy-rsa/pki/index.txt"
    pass := false
    if passphrase != "" {
        pass = true
    }
    certs, err := ReadCerts(rsaIndex)
    if err != nil {
        //      beego.Debug(string(output))
        beego.Error(err)
        //      return err
    }
    Dump(certs)
    exists := false
    for _, v := range certs {
        if v.Details.Name == name {
            exists = true
        }
    }
    if !exists && !pass {
        cmd := exec.Command("/bin/bash", "-c",
            fmt.Sprintf(
                "%s/easyrsa --batch build-client-full %s nopass",
                rsaPath, name))
        cmd.Dir = models.GlobalCfg.OVConfigPath
        output, err := cmd.CombinedOutput()
        if err != nil {
            beego.Debug(string(output))
            beego.Error(err)
            return err
        }
        return nil
    }
    if !exists && pass {
        cmd := exec.Command("/bin/bash", "-c",
            fmt.Sprintf(
                "%s/easyrsa --passout=pass:%s build-client-full %s",
                rsaPath, passphrase, name))
        cmd.Dir = models.GlobalCfg.OVConfigPath
        output, err := cmd.CombinedOutput()
        if err != nil {
            beego.Debug(string(output))
            beego.Error(err)
            return err
        }
        return nil
    }
    if exists {
        return err
    }
    return err
}

I've gone so far as changing every return in the library to err, and inserting a fmt.Println(err) in the controller's second "else" statement, but nil is all I ever get back.

CodePudding user response:

So, I was able to figure out how to deal with this. A bit more googling and I found a post that was at least adjacent to what I was trying to accomplish. In the end, I only needed to add/change 3 lines in my certificates library. I needed to import the "errors" library, add a custom error in the form newError := errors.New("Error! There is already a valid or invalid certificate for that name") and change only the last return to return newError. I definitely learned a thing-or-two about how Go handles errors!

Here's the updated code for the certificates library:

    func CreateCertificate(name string, passphrase string) error {
    rsaPath := models.GlobalCfg.OVConfigPath   "easy-rsa"
    rsaIndex := models.GlobalCfg.OVConfigPath   "easy-rsa/pki/index.txt"
    pass := false
    newError := errors.New("Error! There is already a valid or invalid certificate for that name")
    if passphrase != "" {
        pass = true
    }
    certs, err := ReadCerts(rsaIndex)
    if err != nil {
        //      beego.Debug(string(output))
        beego.Error(err)
        //      return err
    }
    Dump(certs)
    exists := false
    for _, v := range certs {
        if v.Details.Name == name {
            exists = true
        }
    }
    if !exists && !pass {
        cmd := exec.Command("/bin/bash", "-c",
            fmt.Sprintf(
                "%s/easyrsa --batch build-client-full %s nopass",
                rsaPath, name))
        cmd.Dir = models.GlobalCfg.OVConfigPath
        output, err := cmd.CombinedOutput()
        if err != nil {
            beego.Debug(string(output))
            beego.Error(err)
            return err
        }
        return nil
    }
    if !exists && pass {
        cmd := exec.Command("/bin/bash", "-c",
            fmt.Sprintf(
                "%s/easyrsa --passout=pass:%s build-client-full %s",
                rsaPath, passphrase, name))
        cmd.Dir = models.GlobalCfg.OVConfigPath
        output, err := cmd.CombinedOutput()
        if err != nil {
            beego.Debug(string(output))
            beego.Error(err)
            return err
        }
        return nil
    }
    return newError
}

Now, if I try to add an OpenVPN client with a name that already exists:

enter image description here

  • Related