diff --git a/entrypoint.sh b/entrypoint.sh index 41b4b68..355e739 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -18,5 +18,10 @@ EOF cap_prefix="-cap_" caps="$cap_prefix$(seq -s ",$cap_prefix" 0 $(cat /proc/sys/kernel/cap_last_cap))" +# TODO: check mode +/usr/bin/jsonrpc2-helper +service supervisor start +supervisorctl start all + # Start API as signal-api user exec setpriv --reuid=1000 --regid=1000 --init-groups --inh-caps=$caps signal-cli-rest-api -signal-cli-config=${SIGNAL_CLI_CONFIG_DIR} diff --git a/src/client/client.go b/src/client/client.go index a2a0915..9355992 100644 --- a/src/client/client.go +++ b/src/client/client.go @@ -17,6 +17,7 @@ import ( "github.com/cyphar/filepath-securejoin" "github.com/gabriel-vasile/mimetype" "github.com/h2non/filetype" + //"github.com/sourcegraph/jsonrpc2"//"net/rpc/jsonrpc" log "github.com/sirupsen/logrus" uuid "github.com/gofrs/uuid" @@ -30,26 +31,36 @@ const groupPrefix = "group." const signalCliV2GroupError = "Cannot create a V2 group as self does not have a versioned profile" type GroupPermission int + const ( - DefaultGroupPermission GroupPermission = iota + 1 + DefaultGroupPermission GroupPermission = iota + 1 EveryMember OnlyAdmins ) -type GroupLinkState int +type SignalCliMode int + const ( - DefaultGroupLinkState GroupLinkState = iota + 1 + Normal SignalCliMode = iota + 1 + Native + JsonRpc +) + +type GroupLinkState int + +const ( + DefaultGroupLinkState GroupLinkState = iota + 1 Enabled EnabledWithApproval Disabled ) func (g GroupPermission) String() string { - return []string{"", "default", "every-member", "only-admins"}[g] + return []string{"", "default", "every-member", "only-admins"}[g] } func (g GroupLinkState) String() string { - return []string{"", "enabled", "enabled-with-approval", "disabled"}[g] + return []string{"", "enabled", "enabled-with-approval", "disabled"}[g] } type GroupEntry struct { @@ -71,15 +82,30 @@ type IdentityEntry struct { SafetyNumber string `json:"safety_number"` } +type SignalCliGroupMember struct { + Number string `json:"number"` + Uuid string `json:"uuid"` +} + type SignalCliGroupEntry struct { - Name string `json:"name"` - Id string `json:"id"` - IsMember bool `json:"isMember"` - IsBlocked bool `json:"isBlocked"` - Members []string `json:"members"` - PendingMembers []string `json:"pendingMembers"` - RequestingMembers []string `json:"requestingMembers"` - GroupInviteLink string `json:"groupInviteLink"` + Name string `json:"name"` + Id string `json:"id"` + IsMember bool `json:"isMember"` + IsBlocked bool `json:"isBlocked"` + Members []SignalCliGroupMember `json:"members"` + PendingMembers []string `json:"pendingMembers"` + RequestingMembers []string `json:"requestingMembers"` + GroupInviteLink string `json:"groupInviteLink"` +} + +type SignalCliIdentityEntry struct { + Number string `json:"number"` + Uuid string `json:"uuid"` + Fingerprint string `json:"fingerprint"` + SafetyNumber string `json:"safetyNumber"` + ScannableSafetyNumber string `json:"scannableSafetyNumber"` + TrustLevel string `json:"trustLevel"` + AddedTimestamp int64 `json:"addedTimestamp"` } type About struct { @@ -252,7 +278,7 @@ func runSignalCli(wait bool, args []string, stdin string) (string, error) { } fullCmd := "" - if(stdin != "") { + if stdin != "" { fullCmd += "echo '" + stdin + "' | " } fullCmd += signalCliBinary + " " + strings.Join(args, " ") @@ -323,19 +349,47 @@ func ConvertGroupIdToInternalGroupId(id string) (string, error) { } type SignalClient struct { - signalCliConfig string - attachmentTmpDir string - avatarTmpDir string + signalCliConfig string + attachmentTmpDir string + avatarTmpDir string + signalCliMode SignalCliMode + jsonRpc2ClientConfig *utils.JsonRpc2ClientConfig + jsonRpc2ClientConfigPath string + jsonRpc2Clients map[string]*JsonRpc2Client } -func NewSignalClient(signalCliConfig string, attachmentTmpDir string, avatarTmpDir string) *SignalClient { +func NewSignalClient(signalCliConfig string, attachmentTmpDir string, avatarTmpDir string, signalCliMode SignalCliMode, + jsonRpc2ClientConfigPath string) *SignalClient { return &SignalClient{ - signalCliConfig: signalCliConfig, - attachmentTmpDir: attachmentTmpDir, - avatarTmpDir: avatarTmpDir, + signalCliConfig: signalCliConfig, + attachmentTmpDir: attachmentTmpDir, + avatarTmpDir: avatarTmpDir, + signalCliMode: signalCliMode, + jsonRpc2ClientConfigPath: jsonRpc2ClientConfigPath, + jsonRpc2Clients: make(map[string]*JsonRpc2Client), } } +func (s *SignalClient) Init() error { + if s.signalCliMode == JsonRpc { + s.jsonRpc2ClientConfig = utils.NewJsonRpc2ClientConfig() + err := s.jsonRpc2ClientConfig.Load(s.jsonRpc2ClientConfigPath) + if err != nil { + return err + } + + tcpPortsNumberMapping := s.jsonRpc2ClientConfig.GetTcpPortsForNumbers() + for number, tcpPort := range tcpPortsNumberMapping { + s.jsonRpc2Clients[number] = NewJsonRpc2Client() + err := s.jsonRpc2Clients[number].Dial("127.0.0.1:" + strconv.FormatInt(tcpPort, 10)) + if err != nil { + return err + } + } + } + return nil +} + func (s *SignalClient) About() About { about := About{SupportedApiVersions: []string{"v1", "v2"}, BuildNr: 2} return about @@ -372,6 +426,13 @@ func (s *SignalClient) SendV1(number string, message string, recipients []string return timestamp, err } +func (s *SignalClient) getJsonRpc2Client(number string) (*JsonRpc2Client, error) { + if val, ok := s.jsonRpc2Clients[number]; ok { + return val, nil + } + return nil, errors.New("Number not registered with JSON-RPC") +} + func (s *SignalClient) SendV2(number string, message string, recps []string, base64Attachments []string) ([]string, error) { if len(recps) == 0 { return []string{}, errors.New("Please provide at least one recipient") @@ -444,49 +505,81 @@ func (s *SignalClient) Receive(number string, timeout int64) (string, error) { } func (s *SignalClient) CreateGroup(number string, name string, members []string, description string, editGroupPermission GroupPermission, addMembersPermission GroupPermission, groupLinkState GroupLinkState) (string, error) { - cmd := []string{"--config", s.signalCliConfig, "-u", number, "updateGroup", "-n", name, "-m"} - cmd = append(cmd, members...) - - if addMembersPermission != DefaultGroupPermission { - cmd = append(cmd, []string{"--set-permission-add-member", addMembersPermission.String()}...) - } - - if editGroupPermission != DefaultGroupPermission { - cmd = append(cmd, []string{"--set-permission-edit-details", editGroupPermission.String()}...) - } - - if groupLinkState != DefaultGroupLinkState { - cmd = append(cmd, []string{"--link", groupLinkState.String()}...) - } - - if description != "" { - cmd = append(cmd, []string{"--description", description}...) - } - - out, err := runSignalCli(true, cmd, "") - if err != nil { - if strings.Contains(err.Error(), signalCliV2GroupError) { - return "", errors.New("Cannot create group - please first update your profile.") + var err error + var rawData string + if s.signalCliMode == JsonRpc { + type Request struct { + Name string `json:"name"` + Members []string `json:"members"` } - return "", err - } + request := Request{Name: name, Members: members} - internalGroupId := getStringInBetween(out, `"`, `"`) + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return "", err + } + rawData, err = jsonRpc2Client.getRaw("updateGroup", request) + if err != nil { + return "", err + } + } else { + cmd := []string{"--config", s.signalCliConfig, "-u", number, "updateGroup", "-n", name, "-m"} + cmd = append(cmd, members...) + + if addMembersPermission != DefaultGroupPermission { + cmd = append(cmd, []string{"--set-permission-add-member", addMembersPermission.String()}...) + } + + if editGroupPermission != DefaultGroupPermission { + cmd = append(cmd, []string{"--set-permission-edit-details", editGroupPermission.String()}...) + } + + if groupLinkState != DefaultGroupLinkState { + cmd = append(cmd, []string{"--link", groupLinkState.String()}...) + } + + if description != "" { + cmd = append(cmd, []string{"--description", description}...) + } + + rawData, err = runSignalCli(true, cmd, "") + if err != nil { + if strings.Contains(err.Error(), signalCliV2GroupError) { + return "", errors.New("Cannot create group - please first update your profile.") + } + return "", err + } + } + internalGroupId := getStringInBetween(rawData, `"`, `"`) groupId := convertInternalGroupIdToGroupId(internalGroupId) + return groupId, nil } func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) { groupEntries := []GroupEntry{} - out, err := runSignalCli(true, []string{"--config", s.signalCliConfig, "--output", "json", "-u", number, "listGroups", "-d"}, "") - if err != nil { - return groupEntries, err + var signalCliGroupEntries []SignalCliGroupEntry + var err error + var rawData string + + if s.signalCliMode == JsonRpc { + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return groupEntries, err + } + rawData, err = jsonRpc2Client.getRaw("listGroups", nil) + if err != nil { + return groupEntries, err + } + } else { + rawData, err = runSignalCli(true, []string{"--config", s.signalCliConfig, "--output", "json", "-u", number, "listGroups", "-d"}, "") + if err != nil { + return groupEntries, err + } } - var signalCliGroupEntries []SignalCliGroupEntry - - err = json.Unmarshal([]byte(out), &signalCliGroupEntries) + err = json.Unmarshal([]byte(rawData), &signalCliGroupEntries) if err != nil { return groupEntries, err } @@ -497,7 +590,13 @@ func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) { groupEntry.Name = signalCliGroupEntry.Name groupEntry.Id = convertInternalGroupIdToGroupId(signalCliGroupEntry.Id) groupEntry.Blocked = signalCliGroupEntry.IsBlocked - groupEntry.Members = signalCliGroupEntry.Members + + members := []string{} + for _, val := range signalCliGroupEntry.Members { + members = append(members, val.Number) + } + groupEntry.Members = members + groupEntry.PendingRequests = signalCliGroupEntry.PendingMembers groupEntry.PendingInvites = signalCliGroupEntry.RequestingMembers groupEntry.InviteLink = signalCliGroupEntry.GroupInviteLink @@ -602,12 +701,9 @@ func (s *SignalClient) GetAttachment(attachment string) ([]byte, error) { } func (s *SignalClient) UpdateProfile(number string, profileName string, base64Avatar string) error { - cmd := []string{"--config", s.signalCliConfig, "-u", number, "updateProfile", "--name", profileName} - - avatarTmpPaths := []string{} - if base64Avatar == "" { - cmd = append(cmd, "--remove-avatar") - } else { + var err error + var avatarTmpPath string + if base64Avatar != "" { u, err := uuid.NewV4() if err != nil { return err @@ -615,7 +711,7 @@ func (s *SignalClient) UpdateProfile(number string, profileName string, base64Av avatarBytes, err := base64.StdEncoding.DecodeString(base64Avatar) if err != nil { - return errors.New("Couldn't decode base64 encoded avatar: " +err.Error()) + return errors.New("Couldn't decode base64 encoded avatar: " + err.Error()) } fType, err := filetype.Get(avatarBytes) @@ -632,51 +728,113 @@ func (s *SignalClient) UpdateProfile(number string, profileName string, base64Av defer f.Close() if _, err := f.Write(avatarBytes); err != nil { - cleanupTmpFiles(avatarTmpPaths) + cleanupTmpFiles([]string{avatarTmpPath}) return err } if err := f.Sync(); err != nil { - cleanupTmpFiles(avatarTmpPaths) + cleanupTmpFiles([]string{avatarTmpPath}) return err } f.Close() - - cmd = append(cmd, []string{"--avatar", avatarTmpPath}...) - avatarTmpPaths = append(avatarTmpPaths, avatarTmpPath) } - _, err := runSignalCli(true, cmd, "") - cleanupTmpFiles(avatarTmpPaths) + if s.signalCliMode == JsonRpc { + type Request struct { + Name string `json:"name"` + Avatar string `json:"avatar,omitempty"` + RemoveAvatar bool `json:"remove-avatar"` + } + request := Request{Name: profileName} + if base64Avatar == "" { + request.RemoveAvatar = true + } else { + request.Avatar = avatarTmpPath + request.RemoveAvatar = false + } + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return err + } + _, err = jsonRpc2Client.getRaw("updateProfile", request) + } else { + cmd := []string{"--config", s.signalCliConfig, "-u", number, "updateProfile", "--name", profileName} + if base64Avatar == "" { + cmd = append(cmd, "--remove-avatar") + } else { + cmd = append(cmd, []string{"--avatar", avatarTmpPath}...) + } + + _, err = runSignalCli(true, cmd, "") + } + + cleanupTmpFiles([]string{avatarTmpPath}) return err } func (s *SignalClient) ListIdentities(number string) (*[]IdentityEntry, error) { - out, err := runSignalCli(true, []string{"--config", s.signalCliConfig, "-u", number, "listIdentities"}, "") - if err != nil { - return nil, err - } - identityEntries := []IdentityEntry{} - keyValuePairs := parseWhitespaceDelimitedKeyValueStringList(out, []string{"NumberAndTrustStatus", "Added", "Fingerprint", "Safety Number"}) - for _, keyValuePair := range keyValuePairs { - numberAndTrustStatus := keyValuePair["NumberAndTrustStatus"] - numberAndTrustStatusSplitted := strings.Split(numberAndTrustStatus, ":") - - identityEntry := IdentityEntry{Number: strings.Trim(numberAndTrustStatusSplitted[0], " "), - Status: strings.Trim(numberAndTrustStatusSplitted[1], " "), - Added: keyValuePair["Added"], - Fingerprint: strings.Trim(keyValuePair["Fingerprint"], " "), - SafetyNumber: strings.Trim(keyValuePair["Safety Number"], " "), + if s.signalCliMode == JsonRpc { + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return nil, err + } + rawData, err := jsonRpc2Client.getRaw("listIdentities", nil) + signalCliIdentityEntries := []SignalCliIdentityEntry{} + err = json.Unmarshal([]byte(rawData), &signalCliIdentityEntries) + if err != nil { + return nil, err + } + for _, signalCliIdentityEntry := range signalCliIdentityEntries { + identityEntry := IdentityEntry{ + Number: signalCliIdentityEntry.Number, + Status: signalCliIdentityEntry.TrustLevel, + Added: strconv.FormatInt(signalCliIdentityEntry.AddedTimestamp, 10), + Fingerprint: signalCliIdentityEntry.Fingerprint, + SafetyNumber: signalCliIdentityEntry.SafetyNumber, + } + identityEntries = append(identityEntries, identityEntry) + } + } else { + rawData, err := runSignalCli(true, []string{"--config", s.signalCliConfig, "-u", number, "listIdentities"}, "") + if err != nil { + return nil, err + } + + keyValuePairs := parseWhitespaceDelimitedKeyValueStringList(rawData, []string{"NumberAndTrustStatus", "Added", "Fingerprint", "Safety Number"}) + for _, keyValuePair := range keyValuePairs { + numberAndTrustStatus := keyValuePair["NumberAndTrustStatus"] + numberAndTrustStatusSplitted := strings.Split(numberAndTrustStatus, ":") + + identityEntry := IdentityEntry{Number: strings.Trim(numberAndTrustStatusSplitted[0], " "), + Status: strings.Trim(numberAndTrustStatusSplitted[1], " "), + Added: keyValuePair["Added"], + Fingerprint: strings.Trim(keyValuePair["Fingerprint"], " "), + SafetyNumber: strings.Trim(keyValuePair["Safety Number"], " "), + } + identityEntries = append(identityEntries, identityEntry) } - identityEntries = append(identityEntries, identityEntry) } return &identityEntries, nil } func (s *SignalClient) TrustIdentity(number string, numberToTrust string, verifiedSafetyNumber string) error { - cmd := []string{"--config", s.signalCliConfig, "-u", number, "trust", numberToTrust, "--verified-safety-number", verifiedSafetyNumber} - _, err := runSignalCli(true, cmd, "") + var err error + if s.signalCliMode == JsonRpc { + type Request struct { + VerifiedSafetyNumber string `json:"verified-safety-number"` + Recipient string `json:"recipient"` + } + request := Request{VerifiedSafetyNumber: verifiedSafetyNumber, Recipient: numberToTrust} + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return err + } + _, err = jsonRpc2Client.getRaw("trust", request) + } else { + cmd := []string{"--config", s.signalCliConfig, "-u", number, "trust", numberToTrust, "--verified-safety-number", verifiedSafetyNumber} + _, err = runSignalCli(true, cmd, "") + } return err } @@ -686,11 +844,37 @@ func (s *SignalClient) BlockGroup(number string, groupId string) error { } func (s *SignalClient) JoinGroup(number string, groupId string) error { - _, err := runSignalCli(true, []string{"--config", s.signalCliConfig, "-u", number, "updateGroup", "-g", groupId}, "") + var err error + if s.signalCliMode == JsonRpc { + type Request struct { + GroupId string `json:"groupId"` + } + request := Request{GroupId: groupId} + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return err + } + _, err = jsonRpc2Client.getRaw("updateGroup", request) + } else { + _, err = runSignalCli(true, []string{"--config", s.signalCliConfig, "-u", number, "updateGroup", "-g", groupId}, "") + } return err } func (s *SignalClient) QuitGroup(number string, groupId string) error { - _, err := runSignalCli(true, []string{"--config", s.signalCliConfig, "-u", number, "quitGroup", "-g", groupId}, "") + var err error + if s.signalCliMode == JsonRpc { + type Request struct { + GroupId string `json:"groupId"` + } + request := Request{GroupId: groupId} + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return err + } + _, err = jsonRpc2Client.getRaw("quitGroup", request) + } else { + _, err = runSignalCli(true, []string{"--config", s.signalCliConfig, "-u", number, "quitGroup", "-g", groupId}, "") + } return err } diff --git a/src/client/jsonrpc2.go b/src/client/jsonrpc2.go new file mode 100644 index 0000000..d1ee56b --- /dev/null +++ b/src/client/jsonrpc2.go @@ -0,0 +1,95 @@ +package client + +import ( + "encoding/json" + "errors" + "net" + "bufio" + uuid "github.com/gofrs/uuid" + log "github.com/sirupsen/logrus" +) + +type JsonRpc2Client struct { + conn net.Conn +} + +func NewJsonRpc2Client() *JsonRpc2Client { + return &JsonRpc2Client{ + } +} + +func (r *JsonRpc2Client) Dial(address string) error { + var err error + r.conn, err = net.Dial("tcp", address) + if err != nil { + return err + } + + return nil +} + +func (r *JsonRpc2Client) getRaw(command string, args interface{}) (string, error) { + type Request struct { + JsonRpc string `json:"jsonrpc"` + Method string `json:"method"` + Id string `json:"id"` + Params interface{} `json:"params,omitempty"` + } + + type Error struct { + Code int `json:"code"` + Message string `json:"message"` + } + + type Response struct { + Id string `json:"id"` + Result json.RawMessage `json:"result"` + Err Error `json:"error"` + } + + u, err := uuid.NewV4() + if err != nil { + return "", err + } + + fullCommand := Request{JsonRpc: "2.0", Method: command, Id: u.String()} + if args != nil { + fullCommand.Params = args + } + + fullCommandBytes, err := json.Marshal(fullCommand) + if err != nil { + return "", err + } + + log.Info("request = ", string(fullCommandBytes)) + + _, err = r.conn.Write([]byte(string(fullCommandBytes) + "\n")) + if err != nil { + return "", err + } + + connbuf := bufio.NewReader(r.conn) + for { + str, err := connbuf.ReadString('\n') + if err != nil { + return "", err + } + + var resp Response + err = json.Unmarshal([]byte(str), &resp) + if err == nil { + if resp.Id == u.String() { + log.Info("Response1 = ", string(resp.Result)) + if resp.Err.Code != 0 { + return "", errors.New(resp.Err.Message) + } + return string(resp.Result), nil + } + } else { + log.Info("Response = ", str) + } + } + + return "", errors.New("no data") +} diff --git a/src/go.mod b/src/go.mod index 3bc5b8d..c561186 100644 --- a/src/go.mod +++ b/src/go.mod @@ -23,5 +23,5 @@ require ( golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect golang.org/x/text v0.3.3 // indirect golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v2 v2.3.0 ) diff --git a/src/go.sum b/src/go.sum index 0199f7c..8401e1a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -16,6 +16,7 @@ github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrP github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.1.2 h1:gaPnPcNor5aZSVCJVSGipcpbgMWiAAj9z182ocSGbHU= github.com/gabriel-vasile/mimetype v1.1.2/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -70,6 +71,7 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/h2non/filetype v1.1.0 h1:Or/gjocJrJRNK/Cri/TDEKFjAR+cfG6eK65NGYB6gBA= github.com/h2non/filetype v1.1.0/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -95,6 +97,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -143,6 +147,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -156,9 +161,11 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -188,8 +195,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/src/main.go b/src/main.go index 064b8d6..172374b 100644 --- a/src/main.go +++ b/src/main.go @@ -73,7 +73,13 @@ func main() { log.Fatal("Couldn't set env variable: ", err.Error()) } - signalClient := client.NewSignalClient(*signalCliConfig, *attachmentTmpDir, *avatarTmpDir) + jsonRpc2ClientConfigPathPath := *signalCliConfig + "/jsonrpc2.yml" + signalClient := client.NewSignalClient(*signalCliConfig, *attachmentTmpDir, *avatarTmpDir, client.JsonRpc, jsonRpc2ClientConfigPathPath) + err = signalClient.Init() + if err != nil { + log.Fatal("Couldn't init Signal Client: ", err.Error()) + } + api := api.NewApi(signalClient) v1 := router.Group("/v1") { diff --git a/src/utils/config.go b/src/utils/config.go new file mode 100644 index 0000000..e364480 --- /dev/null +++ b/src/utils/config.go @@ -0,0 +1,80 @@ +package utils + +import ( + "io/ioutil" + "errors" + "gopkg.in/yaml.v2" +) + +type ConfigEntry struct { + TcpPort int64 `yaml:"tcp_port"` + FifoPathname string `yaml:"fifo_pathname"` +} + +type Config struct { + Entries map[string]ConfigEntry `yaml:"config,omitempty"` +} + +type JsonRpc2ClientConfig struct { + config Config +} + +func NewJsonRpc2ClientConfig() *JsonRpc2ClientConfig { + return &JsonRpc2ClientConfig{ + } +} + +func (c *JsonRpc2ClientConfig) Load(path string) error { + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + err = yaml.Unmarshal(data, &c.config) + if err != nil { + return err + } + + return nil +} + +func (c *JsonRpc2ClientConfig) GetTcpPortForNumber(number string) (int64, error) { + if val, ok := c.config.Entries[number]; ok { + return val.TcpPort, nil + } + + return 0, errors.New("No number found") +} + +func (c *JsonRpc2ClientConfig) GetFifoPathnameForNumber(number string) (string, error) { + if val, ok := c.config.Entries[number]; ok { + return val.FifoPathname, nil + } + + return "", errors.New("No number found") +} + +func (c *JsonRpc2ClientConfig) GetTcpPortsForNumbers() map[string]int64 { + mapping := make(map[string]int64) + for number, val := range c.config.Entries { + mapping[number] = val.TcpPort + } + + return mapping +} + +func (c *JsonRpc2ClientConfig) AddEntry(number string, configEntry ConfigEntry) { + if c.config.Entries == nil { + c.config.Entries = make(map[string]ConfigEntry) + } + c.config.Entries[number] = configEntry +} + +func (c *JsonRpc2ClientConfig) Persist(path string) error { + out, err := yaml.Marshal(&c.config) + if err != nil { + return err + } + + return ioutil.WriteFile(path, out, 0644) +}