Beispiel #1
0
func (server TwilioSMSCallbackServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	periwinkle.Logf("TwilioCallback")
	fmt.Fprintf(w, "Hi there, I love %s!", req.URL.String())

	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		periwinkle.LogErr(locale.UntranslatedError(err))
		return
	}

	values, err := url.ParseQuery(string(body))
	if err != nil {
		periwinkle.LogErr(locale.UntranslatedError(err))
		return
	}

	status := backend.TwilioSMSMessage{
		MessageStatus: values.Get("MessageStatus"),
		ErrorCode:     values.Get("ErrorCode"),
		MessageSID:    values.Get("MessageSid"),
	}
	server.DB.Do(func(db *periwinkle.Tx) {
		status.Save(db)
	})
}
Beispiel #2
0
// Diff two objects, and produce an RFC 6902 JSON Patch.
func NewJSONPatch(a interface{}, b interface{}) (jsonpatch.JSONPatch, locale.Error) {
	// convert a to json
	aBytes, uerr := json.Marshal(a)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	// convert b to json
	bBytes, uerr := json.Marshal(b)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	// diff them
	p, uerr := matt.CreatePatch(aBytes, bBytes)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	pBytes, uerr := json.Marshal(p)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	// return
	var ret jsonpatch.JSONPatch
	uerr = json.Unmarshal(pBytes, &ret)
	return ret, locale.UntranslatedError(uerr)
}
Beispiel #3
0
// DecoderFormData maps multipart/form-data => json.Decoder # because fuckit
func DecoderFormData(r io.Reader, params map[string]string) (interface{}, locale.Error) {
	boundary, ok := params["boundary"]
	if !ok {
		return nil, locale.UntranslatedError(http.ErrMissingBoundary)
	}
	reader := multipart.NewReader(r, boundary)
	form, uerr := reader.ReadForm(0)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	entity := make(map[string]interface{}, len(form.Value)+len(form.File))
	for k, v := range form.Value {
		entity[k] = v
	}
	for k, v := range form.File {
		if _, exists := entity[k]; exists {
			values := entity[k].([]string)
			list := make([]interface{}, len(values)+len(v))
			i := uint(0)
			for _, value := range values {
				list[i] = value
				i++
			}
			for _, value := range v {
				list[i] = value
				i++
			}
			entity[k] = list
		} else {
			entity[k] = v
		}
	}
	return fuckitJSON(entity)
}
Beispiel #4
0
func DeleteUnusedTwilioNumber(db *periwinkle.Tx, num string) locale.Error {
	var twilioNum TwilioNumber
	if result := db.Where("number = ?", num).First(&twilioNum); result.Error != nil {
		if result.RecordNotFound() {
			periwinkle.Logf("The number is already deleted!!!")
			return nil
		}
		dbError(result.Error)
		return locale.UntranslatedError(result.Error)
	}

	var twilioPool TwilioPool
	result := db.Where("number_id = ?", twilioNum.ID).First(&twilioPool)
	if result.Error != nil {
		if result.RecordNotFound() {

			o := db.Where("number = ?", num).Delete(&TwilioNumber{})
			if o.Error != nil {
				dbError(o.Error)
				return locale.UntranslatedError(o.Error)
			}
			periwinkle.Logf("The number is deleted")
			return nil
		}
		dbError(result.Error)
		return locale.UntranslatedError(result.Error)
	}
	periwinkle.Logf("The number is used for a twilio pool")
	return nil
}
Beispiel #5
0
func (l NetJSON) Write(w io.Writer, loc locale.Spec) locale.Error {
	bytes, uerr := json.Marshal(l.Data)
	if uerr != nil {
		return locale.UntranslatedError(uerr)
	}
	_, uerr = w.Write(bytes)
	return locale.UntranslatedError(uerr)
}
Beispiel #6
0
func (e EncoderJSONStr) Write(w io.Writer, l locale.Spec) locale.Error {
	bytes, err := json.Marshal(e.Data.L10NString(l))
	if err != nil {
		return locale.UntranslatedError(err)
	}
	_, err = w.Write(bytes)
	return locale.UntranslatedError(err)
}
Beispiel #7
0
func (o Medium) dbSeed(db *periwinkle.Tx) locale.Error {
	errs := errorList{}
	errHelper(&errs, locale.UntranslatedError(db.Create(&Medium{"email"}).Error))
	errHelper(&errs, locale.UntranslatedError(db.Create(&Medium{"sms"}).Error))
	errHelper(&errs, locale.UntranslatedError(db.Create(&Medium{"mms"}).Error))
	if len(errs) > 0 {
		return errs
	}
	return nil
}
Beispiel #8
0
func checkNumber(config *periwinkle.Cfg, tx *periwinkle.Tx, number backend.TwilioNumber) {
	url := "https://api.twilio.com/2010-04-01/Accounts/" + config.TwilioAccountID + "/Messages.json?To=" + number.Number
	if lastPoll != timeZero {
		url += "&DateSent>=" + strings.Split(lastPoll.UTC().String(), " ")[0]
	}

	req, _ := http.NewRequest("GET", url, nil)
	req.SetBasicAuth(config.TwilioAccountID, config.TwilioAuthToken)
	resp, uerr := (&http.Client{}).Do(req)
	if uerr != nil {
		periwinkle.LogErr(locale.UntranslatedError(uerr))
	}

	defer resp.Body.Close()
	body, uerr := ioutil.ReadAll(resp.Body)
	if uerr != nil {
		periwinkle.LogErr(locale.UntranslatedError(uerr))
	}

	// converts JSON messages
	var page twilio.Paging
	json.Unmarshal([]byte(body), &page)

	for _, message := range page.Messages {
		timeSend, uerr := time.Parse(time.RFC1123Z, message.DateSent)
		if uerr != nil {
			periwinkle.LogErr(locale.UntranslatedError(uerr))
			continue
		}
		if timeSend.Unix() < lastPoll.Unix() {
			periwinkle.Logf("message %q older than our last poll; ignoring", message.Sid)
			continue
		}
		user := backend.GetUserByAddress(tx, "sms", message.From)
		if user == nil {
			periwinkle.Logf("could not figure out which user has number %q", message.From)
			continue
		}
		group := backend.GetGroupByUserAndTwilioNumber(tx, user.ID, message.To)
		if group == nil {
			periwinkle.Logf("could not figure out which group this is meant for: user: %q, number: %q", user.ID, message.To)
			continue
		}
		periwinkle.Logf("received message for group %q", group.ID)
		MessageBuilder{
			Maildir: config.Mailstore,
			Headers: map[string]string{
				"To":      group.ID + "@" + config.GroupDomain,
				"From":    backend.UserAddress{Medium: "sms", Address: message.From}.AsEmailAddress(),
				"Subject": user.ID + ": " + message.Body,
			},
			Body: "",
		}.Done()
	}
}
Beispiel #9
0
// Apply the patch to an object; as if the object were
// marshalled/unmarshalled JSON.
func (patch JSONMergePatch) Apply(in interface{}, out interface{}) locale.Error {
	inBytes, uerr := json.Marshal(in)
	if uerr != nil {
		return locale.UntranslatedError(uerr)
	}
	outBytes, uerr := evan.MergePatch(inBytes, patch)
	if uerr != nil {
		return locale.UntranslatedError(uerr)
	}
	return locale.UntranslatedError(json.Unmarshal(outBytes, out))
}
Beispiel #10
0
// DecoderFormURLEncoded maps application/x-www-form-urlencoded => json.Decoder # because fuckit
func DecoderFormURLEncoded(r io.Reader, params map[string]string) (interface{}, locale.Error) {
	bytes, uerr := ioutil.ReadAll(r)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	entity, uerr := url.ParseQuery(string(bytes))
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	return fuckitJSON(entity)
}
Beispiel #11
0
func (l netLocationsJSON) Write(w io.Writer, loc locale.Spec) locale.Error {
	strs := make([]string, len(l.NetLocations))
	for i, u := range l.NetLocations {
		strs[i] = u.String()
	}
	bytes, uerr := json.Marshal(strs)
	if uerr != nil {
		return locale.UntranslatedError(uerr)
	}
	_, uerr = w.Write(bytes)
	return locale.UntranslatedError(uerr)
}
Beispiel #12
0
// DecoderJSONMergePatch maps application/merge-patch+json => jsonpatch.Patch
func DecoderJSONMergePatch(r io.Reader, params map[string]string) (interface{}, locale.Error) {
	bytes, uerr := ioutil.ReadAll(r)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	var patch jsonpatch.JSONMergePatch
	uerr = json.Unmarshal(bytes, &patch)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	return jsonpatch.Patch(patch), nil
}
Beispiel #13
0
func (l decodeJSONError) Write(w io.Writer, loc locale.Spec) locale.Error {
	data := map[string]interface{}{
		"message": l.message.L10NString(loc),
		"diff":    l.diff,
	}
	bytes, uerr := json.Marshal(data)
	if uerr != nil {
		return locale.UntranslatedError(uerr)
	}
	_, uerr = w.Write(bytes)
	return locale.UntranslatedError(uerr)
}
Beispiel #14
0
func GetAllExistingTwilioNumbers(cfg *periwinkle.Cfg) []string {
	// gets url for the numbers we own in the Twilio Account
	incomingNumURL := "https://api.twilio.com/2010-04-01/Accounts/" + cfg.TwilioAccountID + "/IncomingPhoneNumbers.json"

	client := &http.Client{}

	req, err := http.NewRequest("GET", incomingNumURL, nil)
	if err != nil {
		periwinkle.LogErr(locale.UntranslatedError(err))
		return nil
	}

	req.SetBasicAuth(cfg.TwilioAccountID, cfg.TwilioAuthToken)

	resp, err := client.Do(req)

	if err != nil {
		periwinkle.LogErr(locale.UntranslatedError(err))
		return nil
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		periwinkle.LogErr(locale.UntranslatedError(err))
		return nil
	}

	if resp.StatusCode != 200 {
		periwinkle.Logf("Response code %s", resp.Status)
		return nil
	}

	numbers := IncomingNumbers{}
	if err := json.Unmarshal(body, &numbers); err != nil {
		periwinkle.LogErr(locale.UntranslatedError(err))
		return nil
	}

	if len(numbers.PhoneNumbers) > 0 {

		existingNumbers := make([]string, len(numbers.PhoneNumbers))

		for i, num := range numbers.PhoneNumbers {
			existingNumbers[i] = num.Number
		}

		return existingNumbers

	} else {
		return nil
	}
}
Beispiel #15
0
func fuckitJSON(entity interface{}) (interface{}, locale.Error) {
	str, uerr := json.Marshal(entity)
	if uerr != nil {
		return nil, locale.UntranslatedError(uerr)
	}
	return json.NewDecoder(strings.NewReader(string(str))), nil
}
Beispiel #16
0
// Start the server; does not block.
func (ss *HTTPServer) Start() {
	ss.Server.ConnState = ss.handleConnStateChange
	ss.wg.Add(1)
	go func() {
		defer ss.wg.Done()
		ss.err = locale.UntranslatedError(ss.Server.Serve(ss.Socket))
	}()
}
Beispiel #17
0
func (l netLocationsTXT) Write(w io.Writer, loc locale.Spec) locale.Error {
	for _, line := range l.NetLocations {
		_, uerr := fmt.Fprintln(w, line)
		if uerr != nil {
			return locale.UntranslatedError(uerr)
		}
	}
	return nil
}
Beispiel #18
0
func DbDrop(db *periwinkle.Tx) locale.Error {
	errs := errorList{}
	for i := range tables {
		table := tables[len(tables)-1-i]
		errHelper(&errs, locale.UntranslatedError(db.DropTable(table).Error))
	}
	if len(errs) > 0 {
		return errs
	}
	return nil
}
Beispiel #19
0
// Panic, but a little nicer
func dbError(err error) {
	// TODO: return better messages for Conflict errors.
	switch e := err.(type) {
	case sqlite3.Error:
		if e.Code == sqlite3.ErrConstraint {
			panic(periwinkle.Conflict{locale.UntranslatedError(e)})
		}
		panic(locale.UntranslatedError(e))
	case *mysql.MySQLError:
		// TODO: this list of error numbers might not be
		// complete, or totally correct.  See
		// https://mariadb.com/kb/en/mariadb/mariadb-error-codes/
		switch e.Number {
		case 1022, 1062, 1169, 1216, 1217, 1451, 1452, 1557, 1761, 1762, 1834:
			panic(periwinkle.Conflict{locale.UntranslatedError(e)})
		}
		panic(locale.UntranslatedError(e))
	default:
		panic(locale.Errorf("Programmer Error: the programmer said this is a database error, but it's not: %s", e))
	}
}
Beispiel #20
0
func OpenDB(driver, source string, debug bool) (*periwinkle.DB, locale.Error) {
	db, err := gorm.Open(driver, source)
	if err != nil && driver == "sqlite3" {
		err = db.Exec("PRAGMA foreign_keys = ON").Error
		db.DB().SetMaxOpenConns(1)
	}
	db.LogMode(debug)
	if err != nil {
		return nil, locale.UntranslatedError(err)
	}
	return periwinkle.NewDB(db), nil
}
Beispiel #21
0
// Intro returns the envelope line insertet by Postfix before the RFC
// 822-style message.
func (pm *Message) Intro() (string, locale.Error) {
	if pm.stdin == nil {
		pm.stdin = bufio.NewReader(os.Stdin)
	}
	if pm.intro == nil {
		intro, err := pm.stdin.ReadString('\n')
		if err != nil {
			return "", locale.UntranslatedError(err)
		}
		pm.intro = &intro
	}
	return *pm.intro, nil
}
Beispiel #22
0
func GetConfig(filename string) *periwinkle.Cfg {
	configFile, uerr := os.Open(filename)
	if uerr != nil {
		periwinkle.Logf("Could not open config file: %v", locale.UntranslatedError(uerr))
		os.Exit(int(lsb.EXIT_NOTCONFIGURED))
	}

	config, err := cfg.Parse(configFile)
	if err != nil {
		periwinkle.Logf("Could not parse config file: %v", err)
		os.Exit(int(lsb.EXIT_NOTCONFIGURED))
	}

	return config
}
Beispiel #23
0
func sdGetSocket() (socket net.Listener, err locale.Error) {
	fds := sd.ListenFds(true)
	if fds == nil {
		err = locale.Errorf("Failed to aquire sockets from systemd")
		return
	}
	if len(fds) != 1 {
		err = locale.Errorf("Wrong number of sockets from systemd: expected %d but got %d", 1, len(fds))
		return
	}
	socket, uerr := net.FileListener(fds[0])
	err = locale.UntranslatedError(uerr)
	fds[0].Close()
	return
}
Beispiel #24
0
// Read an entity from the input stream, using the given content type.
func (req *Request) readEntity(router *Router, reader io.Reader, contenttype string) *Response {
	mimetype, params, uerr := mime.ParseMediaType(contenttype)
	if uerr != nil {
		res := router.responseBadRequest(locale.Errorf("Could not parse Content-Type: %v", locale.UntranslatedError(uerr)))
		return &res
	}
	decoder, foundDecoder := router.Decoders[mimetype]
	if !foundDecoder {
		res := router.responseUnsupportedMediaType(locale.Errorf("Unsupported MIME type: " + mimetype))
		return &res
	}
	entity, err := decoder(reader, params)
	if err != nil {
		res := router.responseUnsupportedMediaType(locale.Errorf("Error reading request body (%s): %v", mimetype, err))
		return &res
	}
	req.Entity = entity
	return nil
}
Beispiel #25
0
func (o Group) dbSeed(db *periwinkle.Tx) locale.Error {
	existence := [2]int{2, 2}
	read := [2]int{2, 2}
	post := [3]int{1, 1, 1}
	join := [3]int{1, 1, 1}
	return locale.UntranslatedError(db.Create(&Group{
		ID:                 "test",
		ReadPublic:         read[0],
		ReadConfirmed:      read[1],
		ExistencePublic:    existence[0],
		ExistenceConfirmed: existence[1],
		PostPublic:         post[0],
		PostConfirmed:      post[1],
		PostMember:         post[2],
		JoinPublic:         join[0],
		JoinConfirmed:      join[1],
		JoinMember:         join[2],
		Subscriptions:      []Subscription{},
	}).Error)
}
Beispiel #26
0
func (accept accept) Acceptable(contenttype string) (bool, locale.Error) {
	mediafulltype, mediaparams, uerr := mime.ParseMediaType(contenttype)
	if uerr != nil {
		return false, locale.UntranslatedError(uerr)
	}
	mediatypeParts := strings.SplitN(mediafulltype, "/", 2)
	mediatype := mediatypeParts[0]
	mediasubtype := mediatypeParts[1]

	if accept.Type != mediatype && accept.Type != "*" {
		return false, nil
	}
	if accept.Subtype != mediasubtype && accept.Subtype != "*" {
		return false, nil
	}
	for key, acceptval := range accept.TypeParams {
		mediaval, ok := mediaparams[key]
		if !ok || mediaval != acceptval {
			return false, nil
		}
	}
	return true, nil
}
Beispiel #27
0
func (o Medium) dbSchema(db *periwinkle.Tx) locale.Error {
	return locale.UntranslatedError(db.CreateTable(&o).Error)
}
Beispiel #28
0
func (o UserAddress) dbSchema(db *periwinkle.Tx) locale.Error {
	return locale.UntranslatedError(db.CreateTable(&o).
		AddUniqueIndex("address_idx", "medium", "address").
		//AddUniqueIndex("user_idx", "user_id", "sort_order").
		Error)
}
Beispiel #29
0
func (o Message) dbSchema(db *periwinkle.Tx) locale.Error {
	return locale.UntranslatedError(db.CreateTable(&o).
		AddUniqueIndex("filename_idx", "unique").
		Error)
}
Beispiel #30
0
func (o Subscription) dbSchema(db *periwinkle.Tx) locale.Error {
	return locale.UntranslatedError(db.CreateTable(&o).Error)
}