mirror of
https://github.com/ergochat/ergo.git
synced 2026-02-07 01:48:06 +01:00
fix #2328
* Add API endpoint /ns/passwd to change passwords * New naming scheme for API endpoints under /v1/ns/ * /v1/ns/list no longer returns error responses
This commit is contained in:
parent
2b1dad982f
commit
a3ecfe94cf
84
docs/API.md
84
docs/API.md
@ -39,21 +39,6 @@ This returns:
|
||||
Endpoints
|
||||
=========
|
||||
|
||||
`/v1/account_details`
|
||||
----------------
|
||||
|
||||
This endpoint fetches account details and returns them as JSON. The request is a JSON object with fields:
|
||||
|
||||
* `accountName`: string, name of the account
|
||||
|
||||
The response is a JSON object with fields:
|
||||
|
||||
* `success`: whether the account exists or not
|
||||
* `accountName`: canonical, case-unfolded version of the account name
|
||||
* `email`: email address of the account provided
|
||||
* `registeredAt`: string, registration date/time of the account (in ISO8601 format)
|
||||
* `channels`: array of strings, list of channels the account is registered on or associated with
|
||||
|
||||
`/v1/check_auth`
|
||||
----------------
|
||||
|
||||
@ -67,16 +52,53 @@ The response is a JSON object with fields:
|
||||
* `success`: whether the credentials provided were valid
|
||||
* `accountName`: canonical, case-unfolded version of the account name
|
||||
|
||||
`/v1/rehash`
|
||||
------------
|
||||
`/v1/ns/info`
|
||||
-------------
|
||||
|
||||
This endpoint rehashes the server (i.e. reloads the configuration file, TLS certificates, and other associated data). The body is ignored. The response is a JSON object with fields:
|
||||
This endpoint fetches account details and returns them as JSON. The request is a JSON object with fields:
|
||||
|
||||
* `success`: boolean, indicates whether the rehash was successful
|
||||
* `error`: string, optional, human-readable description of the failure
|
||||
* `accountName`: string, name of the account
|
||||
|
||||
`/v1/saregister`
|
||||
----------------
|
||||
The response is a JSON object with fields:
|
||||
|
||||
* `success`: whether the account exists or not
|
||||
* `accountName`: canonical, case-unfolded version of the account name
|
||||
* `email`: email address of the account provided
|
||||
* `registeredAt`: string, registration date/time of the account (in ISO8601 format)
|
||||
* `channels`: array of strings, list of channels the account is registered on or associated with
|
||||
|
||||
Note: this endpoint was previously named `/v1/account_details`. The old name is still accepted for backwards compatibility.
|
||||
|
||||
`/v1/ns/list`
|
||||
-------------
|
||||
|
||||
This endpoint fetches a list of all accounts. The request body is ignored and can be empty.
|
||||
|
||||
The response is a JSON object with fields:
|
||||
|
||||
* `success`: whether the request succeeded
|
||||
* `accounts`: array of objects, each with fields:
|
||||
* `success`: boolean, whether this individual account query succeeded
|
||||
* `accountName`: string, canonical, case-unfolded version of the account name
|
||||
* `totalCount`: integer, total number of accounts returned
|
||||
|
||||
Note: this endpoint was previously named `/v1/account_list`. The old name is still accepted for backwards compatibility.
|
||||
|
||||
`/v1/ns/passwd`
|
||||
---------------
|
||||
|
||||
This endpoint changes the password of an existing NickServ account. The request is a JSON object with fields:
|
||||
|
||||
* `accountName`: string, name of the account
|
||||
* `passphrase`: string, new passphrase for the account
|
||||
|
||||
The response is a JSON object with fields:
|
||||
|
||||
* `success`: whether the password change succeeded
|
||||
* `errorCode`: string, optional, machine-readable description of the error. Possible values include: `ACCOUNT_DOES_NOT_EXIST`, `INVALID_PASSPHRASE`, `CREDENTIALS_EXTERNALLY_MANAGED`, `UNKNOWN_ERROR`.
|
||||
|
||||
`/v1/ns/saregister`
|
||||
-------------------
|
||||
|
||||
This endpoint registers an account in NickServ, with the same semantics as `NS SAREGISTER`. The request is a JSON object with fields:
|
||||
|
||||
@ -89,22 +111,18 @@ The response is a JSON object with fields:
|
||||
* `errorCode`: string, optional, machine-readable description of the error. Possible values include: `ACCOUNT_EXISTS`, `INVALID_PASSPHRASE`, `UNKNOWN_ERROR`.
|
||||
* `error`: string, optional, human-readable description of the failure.
|
||||
|
||||
`/v1/account_list`
|
||||
-------------------
|
||||
Note: this endpoint was previously named `/v1/saregister`. The old name is still accepted for backwards compatibility.
|
||||
|
||||
This endpoint fetches a list of all accounts. The request body is ignored and can be empty.
|
||||
`/v1/rehash`
|
||||
------------
|
||||
|
||||
The response is a JSON object with fields:
|
||||
|
||||
* `success`: whether the request succeeded
|
||||
* `accounts`: array of objects, each with fields:
|
||||
* `success`: boolean, whether this individual account query succeeded
|
||||
* `accountName`: string, canonical, case-unfolded version of the account name
|
||||
* `totalCount`: integer, total number of accounts returned
|
||||
This endpoint rehashes the server (i.e. reloads the configuration file, TLS certificates, and other associated data). The body is ignored. The response is a JSON object with fields:
|
||||
|
||||
* `success`: boolean, indicates whether the rehash was successful
|
||||
* `error`: string, optional, human-readable description of the failure
|
||||
|
||||
`/v1/status`
|
||||
-------------
|
||||
------------
|
||||
|
||||
This endpoint returns status information about the running Ergo server. The request body is ignored and can be empty.
|
||||
|
||||
|
||||
64
irc/api.go
64
irc/api.go
@ -17,12 +17,23 @@ func newAPIHandler(server *Server) http.Handler {
|
||||
mux: http.NewServeMux(),
|
||||
}
|
||||
|
||||
// server-level functionality:
|
||||
api.mux.HandleFunc("POST /v1/rehash", api.handleRehash)
|
||||
api.mux.HandleFunc("POST /v1/status", api.handleStatus)
|
||||
|
||||
// use Ergo as a source of truth for authentication in other services:
|
||||
api.mux.HandleFunc("POST /v1/check_auth", api.handleCheckAuth)
|
||||
|
||||
// legacy names for /v1/ns endpoints:
|
||||
api.mux.HandleFunc("POST /v1/saregister", api.handleSaregister)
|
||||
api.mux.HandleFunc("POST /v1/account_details", api.handleAccountDetails)
|
||||
api.mux.HandleFunc("POST /v1/account_list", api.handleAccountList)
|
||||
api.mux.HandleFunc("POST /v1/status", api.handleStatus)
|
||||
|
||||
// /v1/ns: nickserv functionality
|
||||
api.mux.HandleFunc("POST /v1/ns/info", api.handleAccountDetails)
|
||||
api.mux.HandleFunc("POST /v1/ns/list", api.handleAccountList)
|
||||
api.mux.HandleFunc("POST /v1/ns/passwd", api.handleNsPasswd)
|
||||
api.mux.HandleFunc("POST /v1/ns/saregister", api.handleSaregister)
|
||||
|
||||
return api
|
||||
}
|
||||
@ -174,6 +185,31 @@ func (a *ergoAPI) handleSaregister(w http.ResponseWriter, r *http.Request) {
|
||||
a.writeJSONResponse(response, w, r)
|
||||
}
|
||||
|
||||
func (a *ergoAPI) handleNsPasswd(w http.ResponseWriter, r *http.Request) {
|
||||
var request apiSaregisterRequest
|
||||
if err := a.decodeJSONRequest(&request, w, r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var response apiGenericResponse
|
||||
err := a.server.accounts.setPassword(request.AccountName, request.Passphrase, true)
|
||||
switch err {
|
||||
case nil:
|
||||
response.Success = true
|
||||
case errAccountDoesNotExist:
|
||||
response.ErrorCode = "ACCOUNT_DOES_NOT_EXIST"
|
||||
case errAccountBadPassphrase, errEmptyCredentials:
|
||||
response.ErrorCode = "INVALID_PASSPHRASE"
|
||||
case errCredsExternallyManaged:
|
||||
response.ErrorCode = "CREDENTIALS_EXTERNALLY_MANAGED"
|
||||
default:
|
||||
a.server.logger.Error("api", "could not change user password:", err.Error())
|
||||
response.ErrorCode = "UNKNOWN_ERROR"
|
||||
}
|
||||
|
||||
a.writeJSONResponse(response, w, r)
|
||||
}
|
||||
|
||||
type apiAccountDetailsResponse struct {
|
||||
apiGenericResponse
|
||||
AccountName string `json:"accountName,omitempty"`
|
||||
@ -244,26 +280,24 @@ func (a *ergoAPI) handleAccountList(w http.ResponseWriter, r *http.Request) {
|
||||
response.TotalCount = len(accounts)
|
||||
|
||||
// Load account details
|
||||
response.Accounts = make([]apiAccountDetailsResponse, len(accounts))
|
||||
for i, account := range accounts {
|
||||
response.Accounts = make([]apiAccountDetailsResponse, 0, len(accounts))
|
||||
for _, account := range accounts {
|
||||
accountData, err := a.server.accounts.LoadAccount(account)
|
||||
if err != nil {
|
||||
response.Accounts[i] = apiAccountDetailsResponse{
|
||||
apiGenericResponse: apiGenericResponse{
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
},
|
||||
}
|
||||
// shouldn't happen
|
||||
continue
|
||||
}
|
||||
|
||||
response.Accounts[i] = apiAccountDetailsResponse{
|
||||
apiGenericResponse: apiGenericResponse{
|
||||
Success: true,
|
||||
response.Accounts = append(
|
||||
response.Accounts,
|
||||
apiAccountDetailsResponse{
|
||||
apiGenericResponse: apiGenericResponse{
|
||||
Success: true,
|
||||
},
|
||||
AccountName: accountData.Name,
|
||||
Email: accountData.Settings.Email,
|
||||
},
|
||||
AccountName: accountData.Name,
|
||||
Email: accountData.Settings.Email,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
response.Success = true
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user