Skip to content

Commit 9c86892

Browse files
committed
Early public release
1 parent f766896 commit 9c86892

30 files changed

+3510
-1
lines changed

Diff for: .github/workflows/build.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [ main, dev ]
6+
pull_request:
7+
branches: [ main, dev ]
8+
9+
jobs:
10+
11+
build:
12+
name: Build
13+
runs-on: ubuntu-latest
14+
steps:
15+
16+
- name: Set up Go 1.18
17+
uses: actions/setup-go@v1
18+
with:
19+
go-version: 1.18
20+
id: go
21+
22+
- name: Check out code into the Go module directory
23+
uses: actions/checkout@v2
24+
25+
- name: Get dependencies
26+
run: |
27+
go get -v -t -d ./...
28+
- name: Build
29+
run: go build -v .

Diff for: README.md

+58-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,58 @@
1-
# directadmin-go
1+
# DirectAdmin Go SDK
2+
Interface with a DirectAdmin installation using Go.
3+
4+
This library supports both the legacy/default DirectAdmin API, as well as their new modern API that's still in active development.
5+
6+
**Note: This is in an experimental state. While it's being used in production, the library is very likely to change (especially in-line with DA's own changes). DA features are being added as needed on our end, but PRs are always welcome!**
7+
8+
**If you wonder why something has been handled in an unusual way, it's most likely a workaround required by one of DA's many quirks.**
9+
10+
## Login as Admin / Reseller / User
11+
To open a session as an admin/reseller/user, follow the following code block:
12+
13+
```go
14+
package main
15+
16+
import (
17+
"encoding/json"
18+
"time"
19+
"github.com/levelzerotechnology/directadmin-go"
20+
)
21+
22+
func main() {
23+
api, err := directadmin.New("https://your.da.address:2222", 5*time.Second)
24+
if err != nil {
25+
panic(err)
26+
}
27+
28+
userCtx, err := api.LoginAsUser("your_username", "some_password_or_key")
29+
if err != nil {
30+
panic(err)
31+
}
32+
33+
usage, err := userCtx.GetMyUserUsage()
34+
if err != nil {
35+
panic(err)
36+
}
37+
38+
userCtx.User.Usage = *usage
39+
}
40+
```
41+
42+
From here, you can call user functions via `userCtx`.
43+
44+
For example, if you wanted to print each of your databases to your terminal:
45+
```go
46+
dbs, err := userCtx.GetDatabases()
47+
if err != nil {
48+
log.Fatalln(err)
49+
}
50+
51+
for _, db := range dbs {
52+
fmt.Println(db.Name)
53+
}
54+
```
55+
56+
## License
57+
58+
BSD licensed. See the [LICENSE](LICENSE) file for details.

Diff for: admin.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package directadmin
2+
3+
import "net/http"
4+
5+
// Admin inherits Reseller which inherits User
6+
type Admin struct {
7+
Reseller
8+
}
9+
10+
type AdminContext struct {
11+
ResellerContext
12+
}
13+
14+
type convertAccount struct {
15+
Account string `json:"account,omitempty"`
16+
Creator string `json:"creator,omitempty"`
17+
}
18+
19+
func (c *AdminContext) ConvertResellerToUser(username string, reseller string) error {
20+
if _, err := c.api.makeRequestN(http.MethodPost, "convert-reseller-to-user", c.credentials, convertAccount{Account: username, Creator: reseller}, nil); err != nil {
21+
return err
22+
}
23+
24+
return nil
25+
}
26+
27+
func (c *AdminContext) ConvertUserToReseller(username string) error {
28+
if _, err := c.api.makeRequestN(http.MethodPost, "convert-user-to-reseller", c.credentials, convertAccount{Account: username}, nil); err != nil {
29+
return err
30+
}
31+
32+
return nil
33+
}
34+
35+
// GetAllUsers (admin) returns an array of all users
36+
func (c *AdminContext) GetAllUsers() ([]string, error) {
37+
var users []string
38+
39+
if _, err := c.api.makeRequest(http.MethodGet, "API_SHOW_ALL_USERS", c.credentials, nil, &users); err != nil {
40+
return nil, err
41+
}
42+
43+
return users, nil
44+
}
45+
46+
// GetResellers (admin) returns an array of all resellers
47+
func (c *AdminContext) GetResellers() ([]string, error) {
48+
var users []string
49+
50+
if _, err := c.api.makeRequest(http.MethodGet, "API_SHOW_RESELLERS", c.credentials, nil, &users); err != nil {
51+
return nil, err
52+
}
53+
54+
return users, nil
55+
}
56+
57+
// TODO: finish implementation
58+
func (c *AdminContext) GetResellersWithUsage() ([]string, error) {
59+
var users []string
60+
61+
if _, err := c.api.makeRequest(http.MethodGet, "RESELLER_SHOW", c.credentials, nil, &users); err != nil {
62+
return nil, err
63+
}
64+
65+
return users, nil
66+
}
67+
68+
func (c *AdminContext) MoveUserToReseller(username string, reseller string) error {
69+
if _, err := c.api.makeRequestN(http.MethodPost, "change-user-creator", c.credentials, convertAccount{Account: username, Creator: reseller}, nil); err != nil {
70+
return err
71+
}
72+
73+
return nil
74+
}

Diff for: auth.go

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package directadmin
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
"time"
9+
)
10+
11+
type credentials struct {
12+
username string
13+
passkey string
14+
}
15+
16+
type LoginHistory struct {
17+
Attempts int `json:"attempts"`
18+
Host string `json:"host"`
19+
Timestamp time.Time `json:"timestamp"`
20+
}
21+
22+
func (c *AdminContext) GetLoginHistory() ([]*LoginHistory, error) {
23+
var loginHistory []*LoginHistory
24+
25+
if _, err := c.api.makeRequestN(http.MethodGet, "login-history", c.credentials, nil, &loginHistory); err != nil {
26+
return nil, fmt.Errorf("failed to get login history: %v", err)
27+
}
28+
29+
if len(loginHistory) == 0 {
30+
return nil, fmt.Errorf("no login history found")
31+
}
32+
33+
return loginHistory, nil
34+
}
35+
36+
func (c *UserContext) GetMyUsername() string {
37+
// if user is logged in via reseller, we need to remove the reseller username from the context's username
38+
if strings.Contains(c.credentials.username, "|") {
39+
return strings.Split(c.credentials.username, "|")[1]
40+
}
41+
42+
return c.credentials.username
43+
}
44+
45+
func (c *UserContext) Login() error {
46+
var response apiGenericResponse
47+
48+
if _, err := c.api.makeRequest(http.MethodGet, "API_LOGIN_TEST", c.credentials, nil, &response); err != nil {
49+
return err
50+
}
51+
52+
if response.Success != "Login OK" {
53+
return errors.New("login failed")
54+
}
55+
56+
return nil
57+
}
58+
59+
// LoginAsAdmin verifies the provided credentials against the DA API, then returns an admin-level context.
60+
// The passkey can either be the user's password, or a login key
61+
func (a *API) LoginAsAdmin(username string, passkey string) (*AdminContext, error) {
62+
userCtx, err := a.login(username, passkey)
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
adminCtx := AdminContext{
68+
ResellerContext{
69+
UserContext: *userCtx,
70+
},
71+
}
72+
73+
if adminCtx.User.Config.UserType != AccountRoleAdmin {
74+
return nil, fmt.Errorf("account is not an Admin, it is a %v", adminCtx.User.Config.UserType)
75+
}
76+
77+
return &adminCtx, nil
78+
}
79+
80+
// LoginAsReseller verifies the provided credentials against the DA API, then returns a reseller-level context.
81+
// The passkey can either be the user's password, or a login key
82+
func (a *API) LoginAsReseller(username string, passkey string) (*ResellerContext, error) {
83+
userCtx, err := a.login(username, passkey)
84+
if err != nil {
85+
return nil, err
86+
}
87+
88+
resellerCtx := ResellerContext{
89+
UserContext: *userCtx,
90+
}
91+
92+
if resellerCtx.User.Config.UserType != AccountRoleReseller {
93+
return nil, fmt.Errorf("account is not an Reseller, it is a %v", resellerCtx.User.Config.UserType)
94+
}
95+
96+
return &resellerCtx, nil
97+
}
98+
99+
// LoginAsUser verifies the provided credentials against the DA API, then returns a user-level context.
100+
// The passkey can either be the user's password, or a login key
101+
func (a *API) LoginAsUser(username string, passkey string) (*UserContext, error) {
102+
userCtx, err := a.login(username, passkey)
103+
if err != nil {
104+
return nil, err
105+
}
106+
107+
if userCtx.User.Config.UserType != AccountRoleUser {
108+
return nil, fmt.Errorf("account is not a User, it is a %v", userCtx.User.Config.UserType)
109+
}
110+
111+
return userCtx, nil
112+
}
113+
114+
func (c *AdminContext) LoginAsMyReseller(username string) (*ResellerContext, error) {
115+
return c.api.LoginAsReseller(c.credentials.username+"|"+username, c.credentials.passkey)
116+
}
117+
118+
func (c *ResellerContext) LoginAsMyUser(username string) (*UserContext, error) {
119+
return c.api.LoginAsUser(c.credentials.username+"|"+username, c.credentials.passkey)
120+
}
121+
122+
func (a *API) login(username string, passkey string) (*UserContext, error) {
123+
userCtx := UserContext{
124+
api: a,
125+
credentials: credentials{
126+
username: username,
127+
passkey: passkey,
128+
},
129+
}
130+
131+
if err := userCtx.Login(); err != nil {
132+
return nil, err
133+
}
134+
135+
userConfig, err := userCtx.GetMyUserConfig()
136+
if err != nil {
137+
return nil, err
138+
}
139+
140+
userCtx.User.Config = *userConfig
141+
142+
return &userCtx, nil
143+
}

0 commit comments

Comments
 (0)