Skip to content

Commit

Permalink
Take a slice of users for orders
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ejcx committed Jan 29, 2016
1 parent 9292e13 commit 6991a38
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 77 deletions.
81 changes: 45 additions & 36 deletions README.md
Expand Up @@ -253,70 +253,79 @@ 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"}'
{
"77da1cfd8962fb9685c15c84":{
"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
Expand Down
1 change: 1 addition & 0 deletions cmd/ro/main.go
Expand Up @@ -220,6 +220,7 @@ func runOrder() {
Uses: uses,
Duration: duration,
Labels: processCSL(labels),
Users: processCSL(users),
}
resp, err := roServer.Order(req)
processError(err)
Expand Down
38 changes: 28 additions & 10 deletions core/core.go
Expand Up @@ -118,6 +118,7 @@ type OrderRequest struct {
Password string
Duration string
Uses int
Users []string
EncryptedData []byte
Labels []string
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -780,6 +796,7 @@ func Order(jsonIn []byte) (out []byte, err error) {
duration,
adminsDelegated,
owners,
o.Users,
o.Labels,
numDelegated)
orders.Orders[orderNum] = ord
Expand All @@ -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)
}
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
23 changes: 17 additions & 6 deletions index.html
Expand Up @@ -148,6 +148,8 @@ <h3>Create User</h3>
<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 />
Expand Down Expand Up @@ -338,21 +340,25 @@ <h3>Create Order</h3>
</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>
<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 />
</div>
</div>
<div class="form-group row">
<div class="col-md-6">
<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">
<div class="col-md-12">
<label for="owners-data">Encrypted Data</label>
Expand Down Expand Up @@ -724,6 +730,11 @@ <h3>Create Delegation Link</h3>
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,
Expand Down
56 changes: 37 additions & 19 deletions order/order.go
Expand Up @@ -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
}

Expand All @@ -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
}

Expand All @@ -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 {
Expand All @@ -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{
Expand All @@ -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)
}
Expand All @@ -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
}
Expand Down

0 comments on commit 6991a38

Please sign in to comment.