feat: inital commit

This commit is contained in:
Marco98
2025-11-11 13:41:51 +01:00
commit b00c239a8b
20 changed files with 1020 additions and 0 deletions

163
pkg/mailcow/main.go Normal file
View File

@@ -0,0 +1,163 @@
package mailcow
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
const (
ConstAPIKeyHeaderName = "X-API-Key" //nolint:gosec
)
type client struct {
httpClient *http.Client
baseURL string
apiKey string
}
func New(
httpClient *http.Client,
baseURL,
apiKey string,
) Client {
return &client{
baseURL: baseURL,
apiKey: apiKey,
httpClient: httpClient,
}
}
type Client interface {
GetMailboxes(ctx context.Context) ([]Mailbox, error)
GetAppPasswords(ctx context.Context, username string) ([]AppPassword, error)
DeleteAppPasswords(ctx context.Context, ids []int) error
CreateAppPassword(ctx context.Context, username, appname, password, protocols string) error
}
func (c *client) GetMailboxes(ctx context.Context) ([]Mailbox, error) {
reqURL, err := url.JoinPath(c.baseURL, "api/v1/get/mailbox/all")
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
if err != nil {
return nil, err
}
req.Header.Add(ConstAPIKeyHeaderName, c.apiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %s", resp.Status)
}
mb := make([]Mailbox, 0)
if err := json.NewDecoder(resp.Body).Decode(&mb); err != nil {
return nil, err
}
return mb, nil
}
func (c *client) GetAppPasswords(ctx context.Context, username string) ([]AppPassword, error) {
reqURL, err := url.JoinPath(c.baseURL, "/api/v1/get/app-passwd/all", username)
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
if err != nil {
return nil, err
}
req.Header.Add(ConstAPIKeyHeaderName, c.apiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %s", resp.Status)
}
ap := make([]AppPassword, 0)
if err := json.NewDecoder(resp.Body).Decode(&ap); err != nil {
if strings.HasPrefix(err.Error(), "json: cannot unmarshal object into Go value of type []") {
return []AppPassword{}, nil
}
return nil, err
}
return ap, nil
}
func (c *client) DeleteAppPasswords(ctx context.Context, ids []int) error {
if len(ids) == 0 {
return nil
}
reqURL, err := url.JoinPath(c.baseURL, "api/v1/delete/app-passwd")
if err != nil {
return err
}
reqBytes, err := json.Marshal(ids)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(reqBytes))
if err != nil {
return err
}
req.Header.Add(ConstAPIKeyHeaderName, c.apiKey)
req.Header.Add("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %s", resp.Status)
}
return nil
}
func (c *client) CreateAppPassword(ctx context.Context, username, appname, password, protocols string) error {
reqURL, err := url.JoinPath(c.baseURL, "api/v1/add/app-passwd")
if err != nil {
return err
}
reqStruct := struct {
Username string `json:"username"`
AppName string `json:"app_name"`
Password string `json:"app_passwd"`
Password2 string `json:"app_passwd2"`
Active string `json:"active"`
Protocols string `json:"protocols"`
}{
Username: username,
AppName: appname,
Password: password,
Password2: password,
Active: "1",
Protocols: protocols,
}
reqBytes, err := json.Marshal(reqStruct)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(reqBytes))
if err != nil {
return err
}
req.Header.Add(ConstAPIKeyHeaderName, c.apiKey)
req.Header.Add("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %s", resp.Status)
}
return nil
}

21
pkg/mailcow/structs.go Normal file
View File

@@ -0,0 +1,21 @@
package mailcow
type Mailbox struct {
Username string `json:"username"`
Active int `json:"active"`
ActiveInt int `json:"active_int"`
Domain string `json:"domain"`
Name string `json:"name"`
LocalPart string `json:"local_part"`
}
func (mb *Mailbox) IsActive() bool {
return mb.Active == 1 && mb.ActiveInt == 1
}
type AppPassword struct {
ID int `json:"id"`
Name string `json:"name"`
Mailbox string `json:"mailbox"`
Domain string `json:"domain"`
}