1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"encoding/base64"
8	"regexp"
9	"strings"
10)
11
12type Base64Finder struct {
13	input        string
14	lines        []string
15	base64blocks []string
16}
17
18var b64FindRE = regexp.MustCompile(`^\s*(([a-zA-Z0-9/+_-]+)(={0,3}))\s*$`)
19
20func NewBase64Finder(i string) *Base64Finder {
21	return &Base64Finder{input: i}
22}
23
24func (s *Base64Finder) split() {
25	s.lines = strings.Split(s.input, "\n")
26}
27
28func (s *Base64Finder) findAll() {
29	i := 0
30	for i >= 0 {
31		var msg string
32		msg, i = s.findOne(i)
33		if len(msg) > 0 {
34			s.base64blocks = append(s.base64blocks, msg)
35		}
36	}
37}
38
39func (s *Base64Finder) search(searchFor []byte, url bool) bool {
40
41	var encoding *base64.Encoding
42
43	if url {
44		encoding = base64.URLEncoding
45	} else {
46		encoding = base64.StdEncoding
47	}
48
49	i := 0
50	for i >= 0 {
51		var msg string
52		msg, i = s.findOne(i)
53		if len(msg) > 0 {
54			buf, err := encoding.DecodeString(msg)
55			if err == nil && FastByteArrayEq(searchFor, buf) {
56				return true
57			}
58		}
59	}
60
61	return false
62}
63
64func (s *Base64Finder) findOne(i int) (string, int) {
65	var parts []string
66	l := len(s.lines)
67	state := 0
68
69	for ; i < l; i++ {
70		line := s.lines[i]
71		match := b64FindRE.FindStringSubmatch(line)
72		if match != nil {
73			state = 1
74			parts = append(parts, match[1])
75			if len(match[3]) > 0 {
76				// A terminal "=" character means jump on out
77				i++
78				break
79			}
80		} else if state == 1 {
81			break
82		}
83
84		// wait until next time
85	}
86	if i == l {
87		i = -1
88	}
89	ret := strings.Join(parts, "")
90	return ret, i
91}
92
93func (s *Base64Finder) Run() []string {
94	s.split()
95	s.findAll()
96	return s.base64blocks
97}
98
99func FindBase64Blocks(s string) []string {
100	eng := NewBase64Finder(s)
101	return eng.Run()
102}
103
104func FindFirstBase64Block(s string) string {
105	v := FindBase64Blocks(s)
106	if len(v) > 0 {
107		return v[0]
108	}
109	return ""
110}
111
112var snipRE = regexp.MustCompile(`(([a-zA-Z0-9/+_-]+)(={0,3}))`)
113
114func FindBase64Snippets(s string) []string {
115	return snipRE.FindAllString(s, -1)
116}
117
118func FindBase64Block(s string, pattern []byte, url bool) bool {
119	eng := NewBase64Finder(s)
120	eng.split()
121	return eng.search(pattern, url)
122}
123