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

Provider Notion #470

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions cmd/integration-test/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
// "smtp": &smtp{},
// "pushover": &pushover{},
"gotify": &gotify{},
"notion": &notion{},
}
)

Expand Down
6 changes: 6 additions & 0 deletions cmd/integration-test/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ func (h *gotify) Execute() error {
return run("gotify")
}

type notion struct{}

func (h *notion) Execute() error {
return run("notion")
}

func errIncorrectResultsCount(results []string) error {
return fmt.Errorf("incorrect number of results %s", strings.Join(results, "\n\t"))
}
5 changes: 5 additions & 0 deletions cmd/integration-test/test-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ gotify:
gotify_token: "${GOTIFY_APP_TOKEN}"
gotify_format: "{{data}}"
gotify_disabletls: true
notion:
- id: "notion"
notion_api_key: "${notion_api_key}"
notion_database_id: "${notion_database_id}"
notion_in_page_title: "${notion_in_page_title}" # optional
61 changes: 61 additions & 0 deletions pkg/providers/notion/notion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package notion

import (
"fmt"
"time"

"go.uber.org/multierr"

"github.com/projectdiscovery/gologger"
sliceutil "github.com/projectdiscovery/utils/slice"
)

type Provider struct {
Notion []*Options `yaml:"notion,omitempty"`
counter int
}

type Options struct {
ID string `yaml:"id,omitempty"`
NotionAPIKey string `yaml:"notion_api_key,omitempty"`
NotionDatabaseId string `yaml:"notion_database_id,omitempty"`
NotionInPageTitle string `yaml:"notion_in_page_title,omitempty"` // optional
}

func New(options []*Options, ids []string) (*Provider, error) {
provider := &Provider{}

for _, o := range options {
if len(ids) == 0 || sliceutil.Contains(ids, o.ID) {
provider.Notion = append(provider.Notion, o)
}
}

provider.counter = 0

return provider, nil
}

func (p *Provider) Send(message, CliFormat string) error {
var errs []error
for _, pr := range p.Notion {

newPage := func() Page {
if pr.NotionInPageTitle != "" {
titleWithTimestamp := fmt.Sprintf("%s %s", pr.NotionInPageTitle, time.Now().Format("2006-01-02 15:04:05 MST"))
return pr.CreateInpageText(titleWithTimestamp, message)
}
return pr.CreateNormalText(message)

}()

if success := pr.CreatePage(newPage); success != nil {
err := fmt.Errorf("failed to send notion notification for id: %s", pr.ID)
errs = append(errs, err)
continue
}

gologger.Verbose().Msgf("Notion notification sent for id: %s", pr.ID)
}
return multierr.Combine(errs...)
}
116 changes: 116 additions & 0 deletions pkg/providers/notion/notion_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package notion

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
_ "net/http"
"strings"
)

const notionApiUrl string = "https://api.notion.com/v1/"

func (options *Options) CreatePage(page Page) error {
url := strings.Join([]string{notionApiUrl, "pages/"}, "")
apiKey := options.NotionAPIKey
requestBody := map[string]interface{}{
"parent": map[string]string{
"database_id": page.ParentId,
},
"properties": page.Properties,
}
if page.Children != nil {
requestBody["children"] = page.Children
}

jsonBody, err := json.Marshal(requestBody)
if err != nil {
fmt.Println("Error marshaling request body:", err)
persona-twotwo marked this conversation as resolved.
Show resolved Hide resolved
return err
}

req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
if err != nil {
fmt.Println("Error creating request:", err)
return err
}

req.Header.Add("Content-Type", "application/json")
req.Header.Add("Notion-Version", "2022-02-22")
req.Header.Add("Authorization", "Bearer "+apiKey)

client := &http.Client{}
persona-twotwo marked this conversation as resolved.
Show resolved Hide resolved
res, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
return err
}
defer res.Body.Close()

_, err = io.ReadAll(res.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return err
}

if res.StatusCode != 200 {
fmt.Println("Error creating page:", res.Status)
return fmt.Errorf("error creating page: %s", res.Status)
}
return nil
}

func (options *Options) CreateNormalText(text string) Page {
newPage := Page{
ParentId: options.NotionDatabaseId,
Properties: map[string]interface{}{
"Name": map[string]interface{}{
"title": []map[string]interface{}{
{
"text": map[string]string{
"content": text,
},
},
},
},
},
}

return newPage
}

func (options *Options) CreateInpageText(tite string, text string) Page {
newPage := Page{
ParentId: options.NotionDatabaseId,
Properties: map[string]interface{}{
"Name": map[string]interface{}{
"title": []map[string]interface{}{
{
"text": map[string]string{
"content": tite,
},
},
},
},
},
Children: []map[string]interface{}{
{
"type": "code",
"code": map[string]interface{}{
"rich_text": []map[string]interface{}{
{
"type": "text",
"text": map[string]string{
"content": text,
},
},
},
"language": "bash",
},
},
},
}
return newPage
}
7 changes: 7 additions & 0 deletions pkg/providers/notion/notion_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package notion

type Page struct {
ParentId string `json:"parent_id"`
Properties map[string]interface{} `json:"properties"`
Children []map[string]interface{} `json:"children"`
}
11 changes: 11 additions & 0 deletions pkg/providers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/projectdiscovery/notify/pkg/providers/discord"
"github.com/projectdiscovery/notify/pkg/providers/googlechat"
"github.com/projectdiscovery/notify/pkg/providers/gotify"
"github.com/projectdiscovery/notify/pkg/providers/notion"
"github.com/projectdiscovery/notify/pkg/providers/pushover"
"github.com/projectdiscovery/notify/pkg/providers/slack"
"github.com/projectdiscovery/notify/pkg/providers/smtp"
Expand All @@ -30,6 +31,7 @@ type ProviderOptions struct {
GoogleChat []*googlechat.Options `yaml:"googlechat,omitempty"`
Custom []*custom.Options `yaml:"custom,omitempty"`
Gotify []*gotify.Options `yaml:"gotify,omitempty"`
Notion []*notion.Options `yaml:"notion,omitempty"`
}

// Provider is an interface implemented by providers
Expand Down Expand Up @@ -123,6 +125,15 @@ func New(providerOptions *ProviderOptions, options *types.Options) (*Client, err
client.providers = append(client.providers, provider)
}

if providerOptions.Notion != nil && (len(options.Providers) == 0 || sliceutil.Contains(options.Providers, "notion")) {

provider, err := notion.New(providerOptions.Notion, options.IDs)
if err != nil {
return nil, errors.Wrap(err, "could not create notion provider client")
}
client.providers = append(client.providers, provider)
}

return client, nil
}

Expand Down
1 change: 1 addition & 0 deletions pkg/utils/httpreq/httpreq.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (c *Client) Get(url string, response interface{}) error {
if err != nil {
return fmt.Errorf("error creating request: %v", err)
}
defer res.Body.Close()
if err := jsoniter.NewDecoder(res.Body).Decode(&response); err != nil {
return fmt.Errorf("error trying to unmarshal the response: %v", err)
}
Expand Down
Loading