<commit_before>package firebase

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strconv"
	"time"

	"cloud.google.com/go/compute/metadata"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	"github.com/knq/jwt/gserviceaccount"
)

const (
	// DefaultTokenExpiration is the default expiration for generated OAuth2 tokens.
	DefaultTokenExpiration = 1 * time.Hour
)

// requiredScopes are the oauth2 scopes required for Google's service accounts
// when using with firebase.
var requiredScopes = []string{
	"https://www.googleapis.com/auth/userinfo.email",
	"https://www.googleapis.com/auth/firebase.database",
}

// Option is an option to modify a Firebase ref.
type Option func(r *Ref) error

// URL is an option to set Firebase base URL.
func URL(urlstr string) Option {
	return func(r *Ref) error {
		u, err := url.Parse(urlstr)
		if err != nil {
			return fmt.Errorf("could not parse url: %v", err)
		}

		r.url = u

		return nil
	}
}

// ProjectID is an option that sets the Firebase base URL as
// https://<projectID>.firebaseio.com/.
func ProjectID(projectID string) Option {
	return func(r *Ref) error {
		if projectID == "" {
			return errors.New("project id cannot be empty")
		}

		// set url
		err := URL("https://" + projectID + ".firebaseio.com/")(r)
		if err != nil {
			return errors.New("invalid project id")
		}

		return nil
	}
}

// Transport is an option to set the underlying HTTP transport used when making
// requests against a Firebase ref.
func Transport(roundTripper http.RoundTripper) Option {
	return func(r *Ref) error {
		r.transport = roundTripper
		return nil
	}
}

// WatchBufferLen is an option that sets the channel buffer size for the
// returned event channels from Watch and Listen.
func WatchBufferLen(len int) Option {
	return func(r *Ref) error {
		r.watchBufLen = len
		return nil
	}
}

// GoogleServiceAccountCredentialsJSON is an option that loads Google Service
// Account credentials for use with the Firebase ref from a JSON encoded buf.
//
// Google Service Account credentials can be downloaded from the Google Cloud
// console: https://console.cloud.google.com/iam-admin/serviceaccounts/
func GoogleServiceAccountCredentialsJSON(buf []byte) Option {
	return func(r *Ref) error {
		var err error

		// load service account credentials
		gsa, err := gserviceaccount.FromJSON(buf)
		if err != nil {
			return err
		}

		// simple check
		if gsa.ProjectID == "" || gsa.ClientEmail == "" || gsa.PrivateKey == "" {
			return errors.New("google service account credentials missing project_id, client_email or private_key")
		}

		// set ref url
		err = ProjectID(gsa.ProjectID)(r)
		if err != nil {
			return err
		}

		// create token source
		ts, err := gsa.TokenSource(gsa.ClientEmail, nil, requiredScopes...)
		if err != nil {
			return err<commit_msg>Updating to latest gserviceaccount dependency<commit_after>package firebase

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strconv"
	"time"

	"cloud.google.com/go/compute/metadata"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	"github.com/knq/jwt/bearer"
	"github.com/knq/jwt/gserviceaccount"
)

const (
	// DefaultTokenExpiration is the default expiration for generated OAuth2 tokens.
	DefaultTokenExpiration = 1 * time.Hour
)

// requiredScopes are the oauth2 scopes required for Google's service accounts
// when using with firebase.
var requiredScopes = []string{
	"https://www.googleapis.com/auth/userinfo.email",
	"https://www.googleapis.com/auth/firebase.database",
}

// Option is an option to modify a Firebase ref.
type Option func(r *Ref) error

// URL is an option to set Firebase base URL.
func URL(urlstr string) Option {
	return func(r *Ref) error {
		u, err := url.Parse(urlstr)
		if err != nil {
			return fmt.Errorf("could not parse url: %v", err)
		}

		r.url = u

		return nil
	}
}

// ProjectID is an option that sets the Firebase base URL as
// https://<projectID>.firebaseio.com/.
func ProjectID(projectID string) Option {
	return func(r *Ref) error {
		if projectID == "" {
			return errors.New("project id cannot be empty")
		}

		// set url
		err := URL("https://" + projectID + ".firebaseio.com/")(r)
		if err != nil {
			return errors.New("invalid project id")
		}

		return nil
	}
}

// Transport is an option to set the underlying HTTP transport used when making
// requests against a Firebase ref.
func Transport(roundTripper http.RoundTripper) Option {
	return func(r *Ref) error {
		r.transport = roundTripper
		return nil
	}
}

// WatchBufferLen is an option that sets the channel buffer size for the
// returned event channels from Watch and Listen.
func WatchBufferLen(len int) Option {
	return func(r *Ref) error {
		r.watchBufLen = len
		return nil
	}
}

// GoogleServiceAccountCredentialsJSON is an option that loads Google Service
// Account credentials for use with the Firebase ref from a JSON encoded buf.
//
// Google Service Account credentials can be downloaded from the Google Cloud
// console: https://console.cloud.google.com/iam-admin/serviceaccounts/
func GoogleServiceAccountCredentialsJSON(buf []byte) Option {
	return func(r *Ref) error {
		var err error

		// load service account credentials
		gsa, err := gserviceaccount.FromJSON(buf)
		if err != nil {
			return err
		}

		// simple check
		if gsa.ProjectID == "" || gsa.ClientEmail == "" || gsa.PrivateKey == "" {
			return errors.New("google service account credentials missing project_id, client_email or private_key")
		}

		// set ref url
		err = ProjectID(gsa.ProjectID)(r)
		if err != nil {
			return err
		}

		// create token source
		ts, err := gsa.TokenSource(nil, requiredScopes...)
		if err != nil {
			return err
		}

		// add subject
		err = bearer.Claim("sub", gsa.ClientEmail)(ts)
		if err != nil {
			return err
{'fraction_non_alphanumeric': 0.1154174492060782, 'fraction_numerical': 0.0017073587160662455, 'mean_word_length': 3.4854517611026035, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 10, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5402998', 'n_tokens_mistral': 2013, 'n_tokens_neox': 1871, 'n_words': 607}