Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/cleanup create app screen #118

Merged
merged 11 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 50 additions & 51 deletions echo_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,13 @@ func (svc *Service) AppsShowHandler(c echo.Context) error {
appPermissions := []AppPermission{}
svc.db.Where("app_id = ?", app.ID).Find(&appPermissions)

requestMethods := []string{"pay_invoice"}
// because pay_invoice is enabled even
// when there are no permissions set
requestMethods := []string{}
for _, appPerm := range appPermissions {
if appPerm.RequestMethod == NIP_47_PAY_INVOICE_METHOD {
//find the pay_invoice-specific permissions
Copy link
Contributor

@rolznz rolznz Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if there is no pay permission for this app? won't this break? (Edit: for example the expiry will not show on the show screen currently)

Copy link
Contributor

@rolznz rolznz Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be renamed to appPayInvoicePermission?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would name it paySpecificPermission or something like that then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the AppPermission is the wrong place for the expiry, since it should be the same across all permissions for an app?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any problems with it. Yes it will be the same across all permissions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we get the first permission of the app if it exists then to display the expiry in show.html? right now it will not show the expiry for apps that don't have a pay permission

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we really don't wish to give payInvoice special treatment then ig we shouldn't also send the paySpecificPermission to the frontend separately. Let's send ExpiresAt, MaxAmount and BudgetRenewal just like we send BudgetUsage

renewsIn := ""
budgetRenewal := ""
budgetUsage := int64(0)
maxAmount := 0
expiresAt := time.Time{}

for _, appPerm := range appPermissions {
	if expiresAt.isZero() && !appPerm.ExpiresAt.isZero() {
		expiresAt = appPerm.ExpiresAt
	}
	if appPerm.RequestMethod == NIP_47_PAY_INVOICE_METHOD {
		//find the pay_invoice-specific permissions
		if appPerm.MaxAmount > 0 {
			budgetUsage = svc.GetBudgetUsage(&appPerm)
			budgetRenewal = appPerm.BudgetRenewal
			endOfBudget := GetEndOfBudget(budgetRenewal, app.CreatedAt)
			renewsIn = getEndOfBudgetString(endOfBudget)
		}
	}
	requestMethods = append(requestMethods, nip47MethodDescriptions[appPerm.RequestMethod])
}

// and then send all of them to frontend

appPermission = appPerm
} else {
requestMethods = append(requestMethods, appPerm.RequestMethod)
}
requestMethods = append(requestMethods, nip47MethodDescriptions[appPerm.RequestMethod])
}

renewsIn := ""
Expand Down Expand Up @@ -238,6 +236,10 @@ func (svc *Service) AppsNewHandler(c echo.Context) error {
}
disabled := c.QueryParam("editable") == "false"
requestMethods := c.QueryParam("request_methods")
if requestMethods == "" {
rolznz marked this conversation as resolved.
Show resolved Hide resolved
//default
requestMethods = NIP_47_PAY_INVOICE_METHOD
}
budgetEnabled := maxAmount != "" || budgetRenewal != ""
csrf, _ := c.Get(middleware.DefaultCSRFConfig.ContextKey).(string)

Expand All @@ -256,28 +258,40 @@ func (svc *Service) AppsNewHandler(c echo.Context) error {
sess.Save(c.Request(), c.Response())
return c.Redirect(302, fmt.Sprintf("/%s/auth", strings.ToLower(svc.cfg.LNBackendType)))
}
descriptions := []string{}

//construction to return a map with all possible permissions
//and indicate which ones are checked by default in the front-end
type RequestMethodHelper struct {
Description string
Checked bool
}

requestMethodHelper := map[string]*RequestMethodHelper{}
for k, v := range nip47MethodDescriptions {
requestMethodHelper[k] = &RequestMethodHelper{
Description: v,
}
}

for _, m := range strings.Split(requestMethods, " ") {
if _, ok := nip47MethodDescriptions[m]; ok && m != NIP_47_PAY_INVOICE_METHOD {
descriptions = append(descriptions, nip47MethodDescriptions[m])
if _, ok := nip47MethodDescriptions[m]; ok {
requestMethodHelper[m].Checked = true
}
}

return c.Render(http.StatusOK, "apps/new.html", map[string]interface{}{
"User": user,
"Name": appName,
"Pubkey": pubkey,
"ReturnTo": returnTo,
"MaxAmount": maxAmount,
"BudgetRenewal": budgetRenewal,
"ExpiresAt": expiresAt,
"BudgetEnabled": budgetEnabled,
//todo show request methods in html page
//in a readable format
"RequestMethods": requestMethods,
"RequestMethodDescriptions": descriptions,
"Disabled": disabled,
"Csrf": csrf,
"User": user,
"Name": appName,
"Pubkey": pubkey,
"ReturnTo": returnTo,
"MaxAmount": maxAmount,
"BudgetRenewal": budgetRenewal,
"ExpiresAt": expiresAt,
"BudgetEnabled": budgetEnabled,
"RequestMethods": requestMethods,
"RequestMethodHelper": requestMethodHelper,
"Disabled": disabled,
"Csrf": csrf,
})
}

Expand Down Expand Up @@ -319,45 +333,30 @@ func (svc *Service) AppsCreateHandler(c echo.Context) error {
return err
}

// PAY_INVOICE_METHOD permissions
if maxAmount > 0 || !expiresAt.IsZero() {
requestMethods := c.FormValue("RequestMethods")
if requestMethods == "" {
return fmt.Errorf("Won't create an app without request methods.")
rolznz marked this conversation as resolved.
Show resolved Hide resolved
}
//request methods should be space seperated list of known request kinds
methodsToCreate := strings.Split(requestMethods, " ")
for _, m := range methodsToCreate {
//if we don't know this method, we return an error
if _, ok := nip47MethodDescriptions[m]; !ok {
return fmt.Errorf("Did not recognize request method: %s", m)
}
appPermission := AppPermission{
App: app,
RequestMethod: NIP_47_PAY_INVOICE_METHOD,
RequestMethod: m,
ExpiresAt: expiresAt,
//these fields are only relevant for pay_invoice
MaxAmount: maxAmount,
BudgetRenewal: budgetRenewal,
ExpiresAt: expiresAt,
}

err = tx.Create(&appPermission).Error
if err != nil {
return err
}
}

// other method permissions
requestMethods := c.FormValue("RequestMethods")
if requestMethods != "" {
//validate requestMethods
//should be space seperated, and we always create the pay_invoice permission anyway
//only create the get_balance if present now
methodsToCreate := strings.Split(requestMethods, " ")
for _, m := range methodsToCreate {
if m == NIP_47_GET_BALANCE_METHOD {
appPermission := AppPermission{
App: app,
RequestMethod: NIP_47_GET_BALANCE_METHOD,
ExpiresAt: expiresAt,
}

err = tx.Create(&appPermission).Error
if err != nil {
return err
}
}
}
}

// commit transaction
return nil
})
Expand Down
14 changes: 7 additions & 7 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,17 @@ func (svc *Service) hasPermission(app *App, event *nostr.Event, requestMethod st
// No permission for this request method
return false, NIP_47_ERROR_RESTRICTED, fmt.Sprintf("This app does not have permission to request %s", requestMethod)
}
ExpiresAt := appPermission.ExpiresAt
if !ExpiresAt.IsZero() && ExpiresAt.Before(time.Now()) {
svc.Logger.Info("This pubkey is expired")
return false, NIP_47_ERROR_EXPIRED, "This app has expired"
}

if requestMethod == NIP_47_PAY_INVOICE_METHOD {
ExpiresAt := appPermission.ExpiresAt
if !ExpiresAt.IsZero() && ExpiresAt.Before(time.Now()) {
svc.Logger.Info("This pubkey is expired")
return false, NIP_47_ERROR_EXPIRED, "This app has expired"
}

maxAmount := appPermission.MaxAmount
if maxAmount != 0 {
budgetUsage := svc.GetBudgetUsage(&appPermission)

if budgetUsage+paymentRequest.MSatoshi/1000 > int64(maxAmount) {
return false, NIP_47_ERROR_QUOTA_EXCEEDED, "Insufficient budget remaining to make payment"
}
Expand Down
22 changes: 8 additions & 14 deletions views/apps/new.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ <h2 class="font-bold text-2xl font-headline mb-4 dark:text-white">
<p class="mb-4 text-sm font-medium text-gray-900 dark:text-white">Authorize {{ if .Name }}{{ .Name }}{{ else }}the new app{{end}} access to:</p>

<ul class="mb-6">
{{range $key, $value := .RequestMethodHelper}}
{{ if $value.Checked}}
<li class="mb-2 relative pl-6">
<span class="absolute left-0 text-green-500">✓</span>
Send payments from your wallet.
</li>
{{range .RequestMethodDescriptions}}
<li class="mb-2 relative pl-6">
<span class="absolute left-0 text-green-500">✓</span>
{{ . }}
{{ $value.Description }}
</li>
{{end}}
{{end}}
</ul>

{{ if .Disabled }}
Expand Down Expand Up @@ -150,18 +148,14 @@ <h2 class="font-bold text-2xl font-headline mb-4 dark:text-white">
<p class="text-sm font-medium text-gray-900 dark:text-gray-300 mb-1">Set request permissions</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">Finetune the application's permissions.</p>
<ul class="items-center w-full sm:flex">
{{range $key, $value := .RequestMethodHelper}}
<li class="w-full">
<div class="flex items-center pl-3">
<input {{if .RequestMethodDescriptions}}checked{{end}} id="GetBalance" type="checkbox" value="get_balance" class="w-4 h-4 text-purple-700 bg-gray-50 border border-gray-300 rounded focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-surface-00dp dark:border-gray-700">
<label for="GetBalance" class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300">Read your balance</label>
</div>
</li>
<li class="w-full">
<div class="flex items-center pl-3">
<input checked disabled id="PayInvoice" type="checkbox" value="pay_invoice" class="w-4 h-4 text-purple-700 bg-gray-50 border border-gray-300 rounded focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-surface-00dp dark:border-gray-700">
<label for="PayInvoice" class="ml-2 text-sm font-medium text-gray-500 dark:text-gray-400">Send payments</label>
<input {{if $value.Checked }} checked {{end}} id="{{$key}}-id" type="checkbox" value="{{ $key }}" class="w-4 h-4 text-purple-700 bg-gray-50 border border-gray-300 rounded focus:ring-purple-700 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-surface-00dp dark:border-gray-700">
<label for="PayInvoice" class="ml-2 text-sm font-medium text-gray-500 dark:text-gray-400">{{ $value.Description}}</label>
</div>
</li>
{{ end }}
</ul>
</div>
</div>
Expand Down
12 changes: 1 addition & 11 deletions views/apps/show.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,12 @@ <h2 class="font-bold text-2xl font-headline mb-2 dark:text-white">{{.App.Name}}<
<div class="py-4">
<h3 class="text-xl font-headline dark:text-white">Permissions</h3>
<ul class="mt-2 text-sm text-gray-500 dark:text-gray-400">
{{ if .RequestMethods}}
{{range .RequestMethods}}
{{if eq . "pay_invoice"}}
<li class="mb-2 relative pl-6">
<span class="absolute left-0 text-green-500">✓</span>
Send payments from your wallet
{{ . }}
</li>
{{end}}
{{if eq . "get_balance"}}
<li class="mb-2 relative pl-6">
<span class="absolute left-0 text-green-500">✓</span>
View your wallet balance
</li>
{{end}}
{{end}}
{{end}}
{{ if not .AppPermission.ExpiresAt.IsZero}}
<li class="mb-2 relative pl-6">
<p>
Expand Down