Tapir Integtation II
the build was successful Details

This commit is contained in:
Sarah Jamie Lewis 2020-09-21 14:31:45 -07:00
parent 59dd9c34d6
commit 35cd963ec3
12 changed files with 308 additions and 90 deletions

6
go.mod
View File

@ -3,12 +3,12 @@ module cwtch.im/ui
go 1.12
require (
cwtch.im/cwtch v0.3.16
git.openprivacy.ca/openprivacy/connectivity v1.1.4
cwtch.im/cwtch v0.4.0
git.openprivacy.ca/openprivacy/connectivity v1.2.1
git.openprivacy.ca/openprivacy/log v1.0.1
github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d // indirect
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
golang.org/x/crypto v0.0.0-20200420104511-884d27f42877 // indirect
)
)

6
go.sum
View File

@ -8,12 +8,16 @@ cwtch.im/cwtch v0.3.15 h1:Z7fFREwXY728q2YmmwgHL357zAobrsWJ2oPkkGwzvo0=
cwtch.im/cwtch v0.3.15/go.mod h1:iI9q4C3njHFBYQkNEbzMdK6QWPS0Vbkc0FigRHZNTvM=
cwtch.im/cwtch v0.3.16 h1:4M5So2zRDjy5byzd3G8ZrA2ZWObfm/oSIRfMBIFdOuI=
cwtch.im/cwtch v0.3.16/go.mod h1:iI9q4C3njHFBYQkNEbzMdK6QWPS0Vbkc0FigRHZNTvM=
cwtch.im/cwtch v0.4.0 h1:lhGQiYRBqSF0Pif9QttYVL4B1Oy1vc0v3cZejL7c7x4=
cwtch.im/cwtch v0.4.0/go.mod h1:EvZQDbvXNu38m785dWF0MMljqJzwWrNTFT40HvoEAhI=
cwtch.im/tapir v0.1.15 h1:XSCWOvjmNkzMT2IceFgTBXWGKtYfr3a8o+La1s10OhE=
cwtch.im/tapir v0.1.15/go.mod h1:HzezugpEx+nZ3LdyDsl0w6n45IJYnOt8uqldkLWmaqs=
cwtch.im/tapir v0.1.17 h1:2jVZUe1a88tMI4aJPvRTO4Id3NN3PsM62cT5lntEChk=
cwtch.im/tapir v0.1.17/go.mod h1:HzezugpEx+nZ3LdyDsl0w6n45IJYnOt8uqldkLWmaqs=
cwtch.im/tapir v0.1.18 h1:Fs/jL9ZRyel/A1D/BYzIPEVQau8y5BJg44yA+GQDbSM=
cwtch.im/tapir v0.1.18/go.mod h1:/IrAI6CBHfgzsfgRT8WHVb1P9fCCz7+45hfsdkKn8Zg=
cwtch.im/tapir v0.2.0 h1:7MkoR5+uEuPW34/O0GZRidnIjq/01Cfm8nl5IRuqpGc=
cwtch.im/tapir v0.2.0/go.mod h1:xzzZ28adyUXNkYL1YodcHsAiTt3IJ8Loc29YVn9mIEQ=
git.openprivacy.ca/openprivacy/connectivity v1.1.0/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
git.openprivacy.ca/openprivacy/connectivity v1.1.1 h1:hKxBOmxP7Jdu3K1BJ93mRtKNiWUoP6YHt/o2snE2Z0w=
git.openprivacy.ca/openprivacy/connectivity v1.1.1/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
@ -25,6 +29,8 @@ git.openprivacy.ca/openprivacy/connectivity v1.1.4 h1:/I9epvNNjM8rR/q5y9Y63D9/aP
git.openprivacy.ca/openprivacy/connectivity v1.1.4/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
git.openprivacy.ca/openprivacy/connectivity v1.2.0 h1:dbZ5CRl11vg3BNHdzRKSlDP8OUtDB+mf6FkxMVf73qw=
git.openprivacy.ca/openprivacy/connectivity v1.2.0/go.mod h1:B7vzuVmChJtSKoh0ezph5vu6DQ0gIk0zHUNG6IgXCcA=
git.openprivacy.ca/openprivacy/connectivity v1.2.1 h1:oRL56TR9ZQnKkGkTIQ9wYbJ2IkOOsi/zLYExYiAS+sE=
git.openprivacy.ca/openprivacy/connectivity v1.2.1/go.mod h1:B7vzuVmChJtSKoh0ezph5vu6DQ0gIk0zHUNG6IgXCcA=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.11 h1:C7QFFzG0p5XKu0zcOIdLGwEpA9uU0BceBM7CfVK5D40=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.11/go.mod h1:yTMps/ZpYS+BNBBvANsNAft28FXrBvFHQauMYNWPrwE=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.13 h1:Z86uL9K47onznY1wP1P/wWfWMbbyvk6xnCp94R180os=

View File

@ -87,7 +87,6 @@ func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool, reloadingAccounts
if e.Data[event.Status] != "running" {
p.Listen()
p.StartPeersConnections()
p.StartGroupConnections()
}
blockUnkownPeers, exists := p.GetAttribute(constants.BlockUnknownPeersSetting)

View File

@ -127,7 +127,7 @@ func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) {
if state == connections.AUTHENTICATED {
loading = true
}
uiManager.UpdateContactStatus(group.GroupID, int(state), loading)
uiManager.UpdateContactStatus(serverOnion, int(state), loading)
} else {
log.Errorf("found group that is nil :/")
}

View File

@ -1,6 +1,7 @@
package ui
import (
"encoding/base64"
"sync"
"cwtch.im/cwtch/app"
@ -82,6 +83,7 @@ type GrandCentralDispatcher struct {
_ func(locale string, zoom float32, theme string) `signal:"SupplySettings"`
_ func(groupID, name, server, invitation string, accepted bool, addrbooknames, addrbookaddrs []string) `signal:"SupplyGroupSettings"`
_ func(onion, nick string, authorization string, storage string) `signal:"SupplyPeerSettings"`
_ func(server string, key_types []string, keys []string) `signal:"SupplyServerSettings"`
// signals emitted from the ui (written in go, below)
// ui
@ -118,6 +120,8 @@ type GrandCentralDispatcher struct {
_ func(onion string) `signal:"storeHistoryForPeer,auto"`
_ func(onion string) `signal:"deleteHistoryForPeer,auto"`
_ func(handle string) `signal:"requestServerSettings,auto"`
_ func() `constructor:"init"`
}
@ -380,6 +384,31 @@ func (this *GrandCentralDispatcher) deleteHistoryForPeer(onion string) {
the.Peer.SetContactAttribute(onion, event.SaveHistoryKey, event.DeleteHistoryConfirmed)
}
func (this *GrandCentralDispatcher) requestServerSettings(groupID string) {
group := the.Peer.GetGroup(groupID)
if group == nil {
log.Errorf("couldn't find group %v", groupID)
return
}
serverInfo := the.Peer.GetContact(group.GroupServer)
key_types := []model.KeyType{model.KeyTypeServerOnion, model.KeyTypeTokenOnion, model.KeyTypePrivacyPass}
var keyNames []string
var keys []string
for _, key_type := range key_types {
log.Debugf("Looking up %v %v", key_type, keyNames)
if key, has := serverInfo.GetAttribute(string(key_type)); has {
keyNames = append(keyNames, string(key_type))
keys = append(keys, key)
}
}
this.SupplyServerSettings(group.GroupServer, keyNames, keys)
}
func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
group := the.Peer.GetGroup(groupID)
@ -397,6 +426,9 @@ func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
contactnames[i] = getNick(contact)
}
this.SupplyGroupSettings(group.GroupID, nick, group.GroupServer, invite, group.Accepted, contactnames, contactaddrs)
status := connections.ConnectionStateToType[group.State]
log.Debugf("Sending New Group Status: %v %v", group.GroupServer, status)
this.UpdateContactStatus(group.GroupServer, int(status), false)
}
func (this *GrandCentralDispatcher) saveGroupSettings(groupID, nick string) {
@ -429,6 +461,29 @@ func (this *GrandCentralDispatcher) importString(str string) {
return
}
if strings.HasPrefix(str, "tofubundle:") {
bundle := strings.Split(str,"||")
this.importString(bundle[0][11:])
this.importString(bundle[1])
return
}
// Server Key Bundles are prefixed with
if strings.HasPrefix(str, "server:") {
bundle, err := base64.StdEncoding.DecodeString(str[7:])
if err == nil {
err := the.Peer.AddServer(string(bundle))
if err == nil {
this.InvokePopup("Successfully Imported Server Key Bundle")
return
}
this.InvokePopup("Error Importing Server Key Bundle: " + err.Error())
return
}
this.InvokePopup("Invalid Server Key Bundle: " + err.Error())
return
}
log.Debugf("importing: %s\n", str)
onion := str
name := onion
@ -441,6 +496,7 @@ func (this *GrandCentralDispatcher) importString(str string) {
this.InvokePopup("not a valid group invite")
return
}
return
}
@ -650,7 +706,9 @@ func (this *GrandCentralDispatcher) loadProfile(onion string) {
contacts := the.Peer.GetContacts()
for i := range contacts {
this.GetUiManager(this.selectedProfile()).AddContact(contacts[i])
if the.Peer.GetContact(contacts[i]).IsServer() == false {
this.GetUiManager(this.selectedProfile()).AddContact(contacts[i])
}
}
groups := the.Peer.GetGroups()
@ -689,7 +747,7 @@ func (this *GrandCentralDispatcher) storeSetting(key, val string) {
func (this *GrandCentralDispatcher) reloadProfileList() {
this.ResetProfileList()
for onion, _ := range the.CwtchApp.ListPeers() {
for onion := range the.CwtchApp.ListPeers() {
AddProfile(this, onion)
}
}

View File

@ -14,11 +14,18 @@ import (
)
func isGroup(id string) bool {
return len(id) == 32
return len(id) == 32 && !isServer(id)
}
func isPeer(id string) bool {
return len(id) == 56
return len(id) == 56 && !isServer(id)
}
// Check if the id is associated with a contact with a KeyTypeServerOnion attribute (which indicates that this
// is a server, not a regular contact or a group
func isServer(id string) bool {
_, ok := the.Peer.GetContactAttribute(id, string(model.KeyTypeServerOnion))
return ok
}
func getOrDefault(id, key string, defaultVal string) string {

23
main.go
View File

@ -8,6 +8,7 @@ import (
"cwtch.im/ui/go/ui"
"cwtch.im/ui/go/ui/android"
"flag"
"fmt"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
"github.com/therecipe/qt/androidextras"
@ -16,6 +17,8 @@ import (
"github.com/therecipe/qt/network"
"github.com/therecipe/qt/qml"
"github.com/therecipe/qt/quickcontrols2"
"io/ioutil"
"math/rand"
"os"
"os/user"
"path"
@ -65,7 +68,7 @@ func main() {
log.ExcludeFromPattern("service.go")
log.ExcludeFromPattern("tor/BaseOnionService.go")
log.ExcludeFromPattern("applications/auth.go")
log.ExcludeFromPattern("connections/engine.go")
//log.ExcludeFromPattern("connections/engine.go")
if os.Getenv("CWTCH_FOLDER") != "" {
the.CwtchDir = os.Getenv("CWTCH_FOLDER")
@ -233,10 +236,20 @@ func loadACN() {
}
var err error
the.ACN, err = tor.NewTorACN(the.CwtchDir, torpath)
if err != nil {
// TODO: turn into UI error: status panel?
log.Errorf("Could not start Tor: %v", err)
os.Exit(1)
if _, ok := err.(*tor.NoTorrcError); ok {
// Stopgap: just dump a basic torrc for now
port := rand.Intn(1000) + 9600
controlPort := port + 1
ioutil.WriteFile(path.Join(the.CwtchDir, "tor", "torrc"), []byte(fmt.Sprintf(`SOCKSPort %v \n ControlPort %v`, port, controlPort)), 0600)
the.ACN, err = tor.NewTorACNWithAuth(the.CwtchDir, torpath, controlPort, tor.NullAuthenticator{})
if err != nil {
// TODO: turn into UI error: status panel?
log.Errorf("Could not start Tor: %v", err)
os.Exit(1)
}
}
}

@ -1 +1 @@
Subproject commit e5e537c79bad4fa1c21a6544a1865287062bade3
Subproject commit 5c33d6ed2c46f5fe039fc6fee3cb690cb562cb23

View File

@ -9,128 +9,177 @@ import QtQuick.Controls 1.4
import "../opaque" as Opaque
import "../opaque/styles"
import "../utils.js" as Utils
import "../opaque/theme"
import "../const"
ColumnLayout { // groupSettingsPane
Opaque.SettingsList { // groupSettingsPane
id: gsp
anchors.fill: parent
property string groupID
property variant addrbook
property bool connected: false
property bool synced: false
Flickable {
settings: Column {
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
clip:true
contentWidth: tehcol.width
contentHeight: tehcol.height
Column {
id: tehcol
width: gsp.width
leftPadding: 10
spacing: 5
Opaque.ScalingLabel {
text: qsTr("server-label") + ":"
}
TextField {
id: txtServer
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
readOnly: true
}
Opaque.Button {
icon: "regular/clipboard"
text: qsTr("copy-btn")
Opaque.Setting {
inline: false
label: qsTr("group-name-label")
field: Opaque.ButtonTextField {
id: txtGroupName
readOnly: false
button_text: qsTr("save-btn")
dropShadowColor: Theme.dropShadowPaneColor
onClicked: {
gcd.popup("copied-clipboard-notification")
//: notification: copied to clipboard
gcd.saveGroupSettings(groupID, txtGroupName.text)
theStack.title = txtGroupName.text
}
}
}
Opaque.Setting {
inline: false
label: qsTr("server-label")
field: Opaque.ButtonTextField {
id: txtServer
readOnly: true
button_text: qsTr("copy-btn")
dropShadowColor: Theme.dropShadowPaneColor
onClicked: {
//: notification: copied to clipboard
gcd.popup(qsTr("copied-to-clipboard-notification"))
txtServer.selectAll()
txtServer.copy()
}
}
}
Opaque.ScalingLabel {
text: qsTr("invitation-label") + ":"
}
Opaque.Setting {
inline: false
label: qsTr("invitation-label")
TextField {
field: Opaque.ButtonTextField {
id: txtInvitation
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
readOnly: true
}
Opaque.Button {
icon: "regular/clipboard"
text: qsTr("copy-btn")
button_text: qsTr("copy-btn")
dropShadowColor: Theme.dropShadowPaneColor
onClicked: {
gcd.popup("copied-clipboard-notification")
//: notification: copied to clipboard
gcd.popup(qsTr("copied-to-clipboard-notification"))
txtInvitation.selectAll()
txtInvitation.copy()
}
}
}
Opaque.ScalingLabel{
text: qsTr("group-name-label") + ":"
}
Opaque.Setting {
property color backgroundColor: parent.color
inline: true
label: qsTr("server-info")
field: Column {
width: parent.width
spacing:10
RowLayout {
width: parent.width
Layout.fillWidth: true
Opaque.ScalingLabel {
text: gsp.connected ? qsTr("server-connectivity-connected") : qsTr("server-connectivity-disconnected")
Layout.alignment: Qt.AlignLeft
}
Opaque.Icon {
backgroundColor: Theme.backgroundPaneColor
id: serverStatusIcon
height: 18
width: 18
Layout.alignment: Qt.AlignRight
iconColor: gsp.connected ? Theme.statusbarOnlineFontColor : Theme.statusbarDisconnectedTorFontColor
source: gcd.assetPath + (gsp.connected ? "core/signal_cellular_4_bar-24px.svg" : "core/signal_cellular_connected_no_internet_4_bar-24px.svg")
}
}
RowLayout {
width: parent.width
Layout.fillWidth: true
TextField {
id: txtGroupName
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
}
Opaque.ScalingLabel {
text: gsp.synced ? qsTr("server-synced") : qsTr("server-not-synced")
Layout.alignment: Qt.AlignLeft
}
Opaque.Icon {
id: serverSyncedStatusIcon
backgroundColor: Theme.backgroundPaneColor
height: 18
width: 18
Layout.alignment: Qt.AlignRight
iconColor : gsp.synced ? Theme.statusbarOnlineFontColor : Theme.statusbarConnectingFontColor
source: gcd.assetPath + (gsp.synced ? "core/syncing-01.svg" : "core/syncing-03.svg")
}
}
Opaque.Button {
text: qsTr("save-btn")
Opaque.Button {
icon: "regular/hdd"
text: qsTr("view-server-info")
anchors.right: parent.right
onClicked: {
gcd.saveGroupSettings(groupID, txtGroupName.text)
theStack.title = txtGroupName.text
theStack.pane = theStack.messagePane
}
}
onClicked: {
gcd.requestServerSettings(gcd.selectedConversation)
theStack.pane = theStack.serverInfoPane
}
}
//: Invite someone to the group
Opaque.ScalingLabel { text: qsTr("invite-to-group-label") }
}
}
ComboBox {
id: cbInvite
//popup.font.pixelSize: 12
width: 200
//font.pixelSize: 20
style: CwtchComboBoxStyle{}
}
Opaque.Button {
text: qsTr("invite-btn")
onClicked: {
gcd.inviteToGroup(addrbook[cbInvite.currentIndex], groupID)
}
}
Column {
width:parent.width * 0.95
anchors.horizontalCenter: parent.horizontalCenter
Opaque.Button {
icon: "regular/trash-alt"
text: qsTr("delete-btn")
anchors.right: parent.right
onClicked: {
gcd.leaveGroup(groupID)
theStack.pane = theStack.emptyPane
}
}
}
}//end of column with padding
}//end of flickable
}
Connections {
target: gcd
onUpdateContactStatus: function(_handle, _status, _loading) {
if (txtServer.text == _handle) {
if (_status >= Const.state_connected) {
gsp.connected = true
serverStatusIcon
if (_status != Const.state_synced) {
gsp.synced = false
} else {
gsp.synced = true
}
} else {
gsp.connected = false
gsp.synced = false
}
}
}
onSupplyGroupSettings: function(gid, name, server, invite, accepted, addrbooknames, addrbookaddrs) {
gsp.groupID = gid
txtGroupName.text = name
txtServer.text = server
txtInvitation.text = invite
cbInvite.model = addrbooknames.map(function(e){return Utils.htmlEscaped(e)})
//cbInvite.model = addrbooknames.map(function(e){return Utils.htmlEscaped(e)})
addrbook = addrbookaddrs
}
}

View File

@ -33,10 +33,10 @@ ColumnLayout {
//: Accept group invite button
text: qsTr("accept-group-btn")
icon: "regular/heart"
onClicked: {
gcd.acceptGroup(gcd.selectedConversation)
gcd.requestGroupSettings(gcd.selectedConversation)
}
onClicked: {
gcd.acceptGroup(gcd.selectedConversation)
gcd.requestGroupSettings(gcd.selectedConversation)
}
}
Opaque.Button {
@ -147,5 +147,11 @@ ColumnLayout {
overlay.accepted = accepted
overlay.inGroup = true
}
onSupplyServerSettings: function(server) {
overlay.name = server
}
}
}

View File

@ -0,0 +1,78 @@
import QtGraphicalEffects 1.0
import QtQuick 2.7
import QtQuick.Controls 2.4
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
import QtQuick.Window 2.11
import QtQuick.Controls 1.4
import "../opaque" as Opaque
import "../opaque/styles"
import "../utils.js" as Utils
import "../opaque/theme"
import "../const"
Opaque.SettingsList { // groupSettingsPane
id: gsp
anchors.fill: parent
property string serverName
property color backgroundColor: parent.color
settings: Column {
anchors.fill: parent
Opaque.Setting {
inline: false
label: qsTr("server-label")
field: Opaque.ButtonTextField {
id: txtServer
readOnly: true
text: serverName;
button_text: qsTr("copy-btn")
dropShadowColor: Theme.dropShadowPaneColor
onClicked: {
//: notification: copied to clipboard
gcd.popup(qsTr("copied-to-clipboard-notification"))
txtServer.selectAll()
txtServer.copy()
}
}
}
}
Connections {
target: gcd
onUpdateContactStatus: function(_handle, _status, _loading) {
if (txtServer.text == _handle) {
if (_status >= Const.state_connected) {
serverStatusIcon.iconColor = Theme.statusbarOnlineFontColor
serverStatusIcon.source = gcd.assetPath + "core/signal_cellular_4_bar-24px.svg"
if (_status != Const.state_synced) {
serverSyncedStatusIcon.iconColor = Theme.statusbarConnectingFontColor
serverSyncedStatusIcon.source = gcd.assetPath + "core/syncing-03.svg"
} else {
serverSyncedStatusIcon.iconColor = Theme.statusbarOnlineFontColor
serverSyncedStatusIcon.source = gcd.assetPath + "core/syncing-01.svg"
}
} else {
serverStatusIcon.iconColor = Theme.statusbarDisconnectedTorFontColor
serverStatusIcon.source = gcd.assetPath + "core/signal_cellular_connected_no_internet_4_bar-24px.svg"
serverSyncedStatusIcon.iconColor = Theme.statusbarDisconnectedTorFontColor
serverSyncedStatusIcon.source = gcd.assetPath + "core/syncing-03.svg"
}
}
}
onSupplyServerSettings: function(server, key_names, keys) {
gsp.serverName = server;
toolbar.setTitle(qsTr("server-settings"));
console.log("Servers: " + key_names);
for (let i=0; i<key_names.length;i++) {
console.log("FOUND SERVER KEY " + key_names[i] + " " + keys[i]);
}
}
}
}

View File

@ -115,6 +115,8 @@ ColumnLayout {
onClicked: function(handle) { profileAddEditPane.reset(); parentStack.pane = parentStack.addEditProfilePane }
}
}
}
}