mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-01-05 04:56:07 +00:00
Take a slice of users for orders
Don't assume that the creator of the order wants the delegations. Instead it's much nicer with our current scheme to take in a big slice of people who want delegations, so that each person who ne eds a delegation doesn't need to make an order.
This commit is contained in:
81
README.md
81
README.md
@@ -253,30 +253,33 @@ Example input JSON format:
|
||||
Order creates a new order and lets other users know delegations are needed.
|
||||
|
||||
Example input JSON format:
|
||||
|
||||
$ curl --cacert server/server.crt https://localhost:8080/order \
|
||||
-d '{"Name":"Alice","Password":"Lewis","Labels": ["Blue","Red"],\
|
||||
"Duration":"1h","Uses":5,"EncryptedData":"ABCDE=="}'
|
||||
{
|
||||
"Admins": [
|
||||
"Bob",
|
||||
"Eve"
|
||||
],
|
||||
"AdminsDelegated": null,
|
||||
"Delegated": 0,
|
||||
"DurationRequested": 3.6e+12,
|
||||
"Labels": [
|
||||
"blue",
|
||||
"red"
|
||||
],
|
||||
"Name": "Alice",
|
||||
"Num": "77da1cfd8962fb9685c15c84",
|
||||
"TimeRequested": "2016-01-25T15:58:41.961906679-08:00"
|
||||
"Admins": [
|
||||
"Bob",
|
||||
"Eve"
|
||||
],
|
||||
"AdminsDelegated": null,
|
||||
"Delegated": 0,
|
||||
"DurationRequested": 3.6e+12,
|
||||
"Labels": [
|
||||
"blue",
|
||||
"red"
|
||||
],
|
||||
"Name": "Alice",
|
||||
"Num": "77da1cfd8962fb9685c15c84",
|
||||
"TimeRequested": "2016-01-25T15:58:41.961906679-08:00",
|
||||
}
|
||||
|
||||
### Orders Outstanding
|
||||
|
||||
Orders Outstanding will return a list of current order numbers
|
||||
|
||||
Example input JSON format:
|
||||
|
||||
$ curl --cacert server/server.crt https://localhost:8080/orderout
|
||||
-d '{"Name":"Alice","Password":"Lewis"}'
|
||||
{
|
||||
@@ -284,39 +287,45 @@ Orders Outstanding will return a list of current order numbers
|
||||
"Name":"Alice",
|
||||
"Num":"77da1cfd8962fb9685c15c84",
|
||||
"TimeRequested":"2016-01-25T15:58:41.961906679-08:00",
|
||||
"DurationRequested":3600000000000,
|
||||
"Delegated":0,"
|
||||
AdminsDelegated":null,
|
||||
"Admins":["Bob, Eve"],
|
||||
"Labels":["Blue","Red"]
|
||||
}
|
||||
"DurationRequested":3600000000000,
|
||||
"Delegated":0,"
|
||||
AdminsDelegated":null,
|
||||
"Admins":["Bob, Eve"],
|
||||
"Labels":["Blue","Red"]
|
||||
}
|
||||
}
|
||||
|
||||
### Order Information
|
||||
|
||||
Example input JSON format:
|
||||
|
||||
$ curl --cacert server/server.crt https://localhost:8080/orderinfo
|
||||
-d '{"Name":"Alice","Password":"Lewis", \
|
||||
"OrderNum":"77da1cfd8962fb9685c15c84"}'
|
||||
"OrderNum":"77da1cfd8962fb9685c15c84"}'
|
||||
{
|
||||
"Admins": [
|
||||
"Bob",
|
||||
"Eve"
|
||||
],
|
||||
"AdminsDelegated": null,
|
||||
"Delegated": 0,
|
||||
"DurationRequested": 3.6e+12,
|
||||
"Labels": [
|
||||
"blue",
|
||||
"red"
|
||||
],
|
||||
"Name": "Alice",
|
||||
"Num": "77da1cfd8962fb9685c15c84",
|
||||
"TimeRequested": "2016-01-25T15:58:41.961906679-08:00"
|
||||
"Admins": [
|
||||
"Bob",
|
||||
"Eve"
|
||||
],
|
||||
"AdminsDelegated": null,
|
||||
"Delegated": 0,
|
||||
"DurationRequested": 3.6e+12,
|
||||
"Labels": [
|
||||
"blue",
|
||||
"red"
|
||||
],
|
||||
"Name": "Alice",
|
||||
"Num": "77da1cfd8962fb9685c15c84",
|
||||
"TimeRequested": "2016-01-25T15:58:41.961906679-08:00"
|
||||
}
|
||||
|
||||
### Order Cancel
|
||||
|
||||
Example input JSON format:
|
||||
|
||||
$ curl --cacert server/server.crt https://localhost:8080/orderinfo
|
||||
-d '{"Name":"Alice","Password":"Lewis", \
|
||||
"OrderNum":"77da1cfd8962fb9685c15c84"}'
|
||||
"OrderNum":"77da1cfd8962fb9685c15c84"}'
|
||||
{"Status":"ok"}
|
||||
|
||||
### Web interface
|
||||
|
||||
@@ -220,6 +220,7 @@ func runOrder() {
|
||||
Uses: uses,
|
||||
Duration: duration,
|
||||
Labels: processCSL(labels),
|
||||
Users: processCSL(users),
|
||||
}
|
||||
resp, err := roServer.Order(req)
|
||||
processError(err)
|
||||
|
||||
38
core/core.go
38
core/core.go
@@ -118,6 +118,7 @@ type OrderRequest struct {
|
||||
Password string
|
||||
Duration string
|
||||
Uses int
|
||||
Users []string
|
||||
EncryptedData []byte
|
||||
Labels []string
|
||||
}
|
||||
@@ -216,19 +217,19 @@ func validateName(name, password string) error {
|
||||
}
|
||||
|
||||
// Init reads the records from disk from a given path
|
||||
func Init(ca, hcKey, hcRoom, hcHost, roHost string) error {
|
||||
func Init(path, hcKey, hcRoom, hcHost, roHost string) error {
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.Printf("core.init failed: %v", err)
|
||||
} else {
|
||||
log.Printf("core.init success: ca=%s", ca)
|
||||
log.Printf("core.init success: path=%s", path)
|
||||
}
|
||||
}()
|
||||
|
||||
if records, err = passvault.InitFrom(ca); err != nil {
|
||||
err = fmt.Errorf("failed to load password vault %s: %s", ca, err)
|
||||
if records, err = passvault.InitFrom(path); err != nil {
|
||||
err = fmt.Errorf("failed to load password vault %s: %s", path, err)
|
||||
}
|
||||
|
||||
var hipchatClient hipchat.HipchatClient
|
||||
@@ -403,9 +404,20 @@ func Delegate(jsonIn []byte) ([]byte, error) {
|
||||
for _, delegatedUser := range s.Users {
|
||||
if orderKey, found := orders.FindOrder(delegatedUser, s.Labels); found {
|
||||
order := orders.Orders[orderKey]
|
||||
order.AdminsDelegated = append(order.AdminsDelegated, s.Name)
|
||||
|
||||
order.Delegated++
|
||||
// Don't re-add names to the list of people who have delegated. Instead
|
||||
// just skip them but make sure we count their delegation
|
||||
if len(order.OwnersDelegated) == 0 {
|
||||
order.OwnersDelegated = append(order.OwnersDelegated, s.Name)
|
||||
} else {
|
||||
for _, ownerName := range order.OwnersDelegated {
|
||||
if ownerName == s.Name {
|
||||
continue
|
||||
}
|
||||
order.OwnersDelegated = append(order.OwnersDelegated, s.Name)
|
||||
order.Delegated++
|
||||
}
|
||||
}
|
||||
orders.Orders[orderKey] = order
|
||||
|
||||
// Notify the hipchat room that there was a new delegator
|
||||
@@ -768,7 +780,11 @@ func Order(jsonIn []byte) (out []byte, err error) {
|
||||
cache.Refresh()
|
||||
orderNum := order.GenerateNum()
|
||||
|
||||
adminsDelegated, numDelegated := cache.DelegateStatus(o.Name, o.Labels, owners)
|
||||
if len(o.Users) == 0 {
|
||||
err = errors.New("Must specify at least one user per order.")
|
||||
jsonStatusError(err)
|
||||
}
|
||||
adminsDelegated, numDelegated := cache.DelegateStatus(o.Users[0], o.Labels, owners)
|
||||
duration, err := time.ParseDuration(o.Duration)
|
||||
if err != nil {
|
||||
jsonStatusError(err)
|
||||
@@ -780,6 +796,7 @@ func Order(jsonIn []byte) (out []byte, err error) {
|
||||
duration,
|
||||
adminsDelegated,
|
||||
owners,
|
||||
o.Users,
|
||||
o.Labels,
|
||||
numDelegated)
|
||||
orders.Orders[orderNum] = ord
|
||||
@@ -789,7 +806,7 @@ func Order(jsonIn []byte) (out []byte, err error) {
|
||||
altOwners := records.GetAltNamesFromName(orders.AlternateName, owners)
|
||||
|
||||
// Let everyone on hipchat know there is a new order.
|
||||
orders.NotifyNewOrder(o.Name, o.Duration, orderNum, o.Labels, o.Uses, altOwners)
|
||||
orders.NotifyNewOrder(o.Duration, orderNum, o.Users, o.Labels, o.Uses, altOwners)
|
||||
if err != nil {
|
||||
return jsonStatusError(err)
|
||||
}
|
||||
@@ -851,7 +868,8 @@ func OrderInfo(jsonIn []byte) (out []byte, err error) {
|
||||
|
||||
return jsonResponse(out)
|
||||
}
|
||||
return
|
||||
|
||||
return jsonStatusError(errors.New("No order with that number"))
|
||||
}
|
||||
|
||||
// OrderCancel will cancel an order given an order num
|
||||
@@ -875,7 +893,7 @@ func OrderCancel(jsonIn []byte) (out []byte, err error) {
|
||||
}
|
||||
|
||||
if ord, ok := orders.Orders[o.OrderNum]; ok {
|
||||
if o.Name == ord.Name {
|
||||
if o.Name == ord.Creator {
|
||||
delete(orders.Orders, o.OrderNum)
|
||||
out = []byte("Successfully removed order")
|
||||
return jsonResponse(out)
|
||||
|
||||
23
index.html
23
index.html
@@ -148,6 +148,8 @@
|
||||
<label for="create-user-pass">Password</label>
|
||||
<input type="password" name="Password" class="form-control" id="create-user-pass" placeholder="Password" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6">
|
||||
<label for="create-user-hipchatname">Hipchat Name</label>
|
||||
<input type="text" name="HipchatName" class="form-control" id="create-hipchatname" placeholder="HipchatName" required />
|
||||
@@ -338,19 +340,23 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6">
|
||||
<label for="order-label">Labels</label>
|
||||
<input type="text" name="Labels" class="form-control" id="order-user-label" placeholder="Labels" required />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="order-duration">Duration</label>
|
||||
<input type="text" name="Duration" class="form-control" id="order-duration" placeholder="Duration (e.g., 2h34m)" required />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="order-uses">Uses</label>
|
||||
<input type="number" name="Uses" class="form-control" id="order-uses" placeholder="5" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6">
|
||||
<label for="order-uses">Uses</label>
|
||||
<input type="number" name="Uses" class="form-control" id="order-uses" placeholder="5" required />
|
||||
<label for="order-name-users">Users to allow <small>(comma separated)</small></label>
|
||||
<input type="text" name="Users" class="form-control" id="order-name-users" placeholder="e.g. Alice, Bob" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="order-label">Labels</label>
|
||||
<input type="text" name="Labels" class="form-control" id="order-user-label" placeholder="Labels" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@@ -724,6 +730,11 @@
|
||||
data.Labels[i] = data.Labels[i].trim();
|
||||
if (data.Labels[i] == "") { data.Labels.splice(i, 1); }
|
||||
}
|
||||
data.Users = data.Users.split(',');
|
||||
for(var i=0, l=data.Users.length; i<l; i++){
|
||||
data.Users[i] = data.Users[i].trim();
|
||||
if (data.Users[i] == "") { data.Users.splice(i, 1); }
|
||||
}
|
||||
|
||||
submit( $form, {
|
||||
data : data,
|
||||
|
||||
@@ -24,14 +24,15 @@ const (
|
||||
)
|
||||
|
||||
type Order struct {
|
||||
Name string
|
||||
Num string
|
||||
Creator string
|
||||
Users []string
|
||||
Num string
|
||||
|
||||
TimeRequested time.Time
|
||||
DurationRequested time.Duration
|
||||
Delegated int
|
||||
AdminsDelegated []string
|
||||
Admins []string
|
||||
OwnersDelegated []string
|
||||
Owners []string
|
||||
Labels []string
|
||||
}
|
||||
|
||||
@@ -52,15 +53,16 @@ type Orderer struct {
|
||||
AlternateName string
|
||||
}
|
||||
|
||||
func CreateOrder(name, orderNum string, time time.Time, duration time.Duration, adminsDelegated, contacts, labels []string, numDelegated int) (ord Order) {
|
||||
ord.Name = name
|
||||
func CreateOrder(name, orderNum string, time time.Time, duration time.Duration, adminsDelegated, contacts, users, labels []string, numDelegated int) (ord Order) {
|
||||
ord.Creator = name
|
||||
ord.Num = orderNum
|
||||
ord.Labels = labels
|
||||
ord.TimeRequested = time
|
||||
ord.DurationRequested = duration
|
||||
ord.AdminsDelegated = adminsDelegated
|
||||
ord.Admins = contacts
|
||||
ord.OwnersDelegated = adminsDelegated
|
||||
ord.Owners = contacts
|
||||
ord.Delegated = numDelegated
|
||||
ord.Users = users
|
||||
return
|
||||
}
|
||||
|
||||
@@ -83,7 +85,7 @@ func NewOrderer(hipchatClient hipchat.HipchatClient) (o Orderer) {
|
||||
func notify(o *Orderer, msg, color string) {
|
||||
o.Hipchat.Notify(msg, color)
|
||||
}
|
||||
func (o *Orderer) NotifyNewOrder(name, duration, orderNum string, labels []string, uses int, owners map[string]string) {
|
||||
func (o *Orderer) NotifyNewOrder(duration, orderNum string, names, labels []string, uses int, owners map[string]string) {
|
||||
labelList := ""
|
||||
for i, label := range labels {
|
||||
if i == 0 {
|
||||
@@ -94,7 +96,18 @@ func (o *Orderer) NotifyNewOrder(name, duration, orderNum string, labels []strin
|
||||
labelList += "," + label
|
||||
}
|
||||
}
|
||||
n := fmt.Sprintf(NewOrder, name, labelList, uses, duration)
|
||||
nameList := ""
|
||||
for i, name := range names {
|
||||
if i == 0 {
|
||||
nameList += name
|
||||
} else {
|
||||
// Never include spaces in something go URI encodes. Go will
|
||||
// add a + to the string, instead of a %20
|
||||
nameList += "," + name
|
||||
}
|
||||
}
|
||||
|
||||
n := fmt.Sprintf(NewOrder, nameList, labelList, uses, duration)
|
||||
notify(o, n, hipchat.RedBackground)
|
||||
for owner, hipchatName := range owners {
|
||||
queryParams := url.Values{
|
||||
@@ -103,7 +116,7 @@ func (o *Orderer) NotifyNewOrder(name, duration, orderNum string, labels []strin
|
||||
"duration": {duration},
|
||||
"uses": {strconv.Itoa(uses)},
|
||||
"ordernum": {orderNum},
|
||||
"delegatee": {name},
|
||||
"delegatee": {nameList},
|
||||
}.Encode()
|
||||
notify(o, fmt.Sprintf(NewOrderLink, hipchatName, o.Hipchat.RoHost, queryParams), hipchat.GreenBackground)
|
||||
}
|
||||
@@ -126,23 +139,28 @@ func (o *Orderer) NotifyOrderFulfilled(name, orderNum string) {
|
||||
notify(o, n, hipchat.PurpleBackground)
|
||||
}
|
||||
|
||||
func (o *Orderer) FindOrder(name string, labels []string) (string, bool) {
|
||||
func (o *Orderer) FindOrder(user string, labels []string) (string, bool) {
|
||||
for key, order := range o.Orders {
|
||||
if name != order.Name {
|
||||
foundLabel := false
|
||||
foundUser := false
|
||||
for _, orderUser := range order.Users {
|
||||
if orderUser == user {
|
||||
foundUser = true
|
||||
}
|
||||
}
|
||||
if !foundUser {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ol := range order.Labels {
|
||||
foundLabel := false
|
||||
foundLabel = false
|
||||
for _, il := range labels {
|
||||
if il == ol {
|
||||
foundLabel = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !foundLabel {
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
if !foundLabel {
|
||||
continue
|
||||
}
|
||||
return key, true
|
||||
}
|
||||
|
||||
@@ -430,6 +430,8 @@ var indexHtml = []byte(`<!DOCTYPE html>
|
||||
<label for="create-user-pass">Password</label>
|
||||
<input type="password" name="Password" class="form-control" id="create-user-pass" placeholder="Password" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6">
|
||||
<label for="create-user-hipchatname">Hipchat Name</label>
|
||||
<input type="text" name="HipchatName" class="form-control" id="create-hipchatname" placeholder="HipchatName" required />
|
||||
@@ -620,19 +622,23 @@ var indexHtml = []byte(`<!DOCTYPE html>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6">
|
||||
<label for="order-label">Labels</label>
|
||||
<input type="text" name="Labels" class="form-control" id="order-user-label" placeholder="Labels" required />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="order-duration">Duration</label>
|
||||
<input type="text" name="Duration" class="form-control" id="order-duration" placeholder="Duration (e.g., 2h34m)" required />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="order-uses">Uses</label>
|
||||
<input type="number" name="Uses" class="form-control" id="order-uses" placeholder="5" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6">
|
||||
<label for="order-uses">Uses</label>
|
||||
<input type="number" name="Uses" class="form-control" id="order-uses" placeholder="5" required />
|
||||
<label for="order-name-users">Users to allow <small>(comma separated)</small></label>
|
||||
<input type="text" name="Users" class="form-control" id="order-name-users" placeholder="e.g. Alice, Bob" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="order-label">Labels</label>
|
||||
<input type="text" name="Labels" class="form-control" id="order-user-label" placeholder="Labels" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@@ -1006,6 +1012,11 @@ var indexHtml = []byte(`<!DOCTYPE html>
|
||||
data.Labels[i] = data.Labels[i].trim();
|
||||
if (data.Labels[i] == "") { data.Labels.splice(i, 1); }
|
||||
}
|
||||
data.Users = data.Users.split(',');
|
||||
for(var i=0, l=data.Users.length; i<l; i++){
|
||||
data.Users[i] = data.Users[i].trim();
|
||||
if (data.Users[i] == "") { data.Users.splice(i, 1); }
|
||||
}
|
||||
|
||||
submit( $form, {
|
||||
data : data,
|
||||
|
||||
Reference in New Issue
Block a user