Compare commits

..

No commits in common. "trunk" and "androidservice" have entirely different histories.

9 changed files with 518 additions and 446 deletions

View File

@ -1,5 +0,0 @@
package constants
// We offer "un-passworded" profiles but our storage encrypts everything with a password. We need an agreed upon
// password to use in that case, that the app case use behind the scenes to password and unlock with
const DefactoPasswordForUnencryptedProfiles = "be gay do crime"

View File

@ -91,12 +91,13 @@ func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.Rea
// HandleImportString handles import strings for groups and servers
func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importString string) error {
if strings.HasPrefix(importString, tofuBundlePrefix) {
bundle := strings.Split(importString, "||")
if len(bundle) == 2 {
err := gf.HandleImportString(peer, bundle[0][len(tofuBundlePrefix):])
// if the server import failed then abort the whole process..
if !strings.HasSuffix(err.Error(), "success") {
if !strings.HasSuffix(err.Error(), "success"){
return features.ConstructResponse(importBundlePrefix, err.Error())
}
return gf.HandleImportString(peer, bundle[1])
@ -113,15 +114,10 @@ func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importStri
return features.ConstructResponse(importBundlePrefix, err.Error())
} else if strings.HasPrefix(importString, groupPrefix) {
//eg: torv3JFDWkXExBsZLkjvfkkuAxHsiLGZBk0bvoeJID9ItYnU=EsEBCiBhOWJhZDU1OTQ0NWI3YmM2N2YxYTM5YjkzMTNmNTczNRIgpHeNaG+6jy750eDhwLO39UX4f2xs0irK/M3P6mDSYQIaOTJjM2ttb29ibnlnaGoyenc2cHd2N2Q1N3l6bGQ3NTNhdW8zdWdhdWV6enB2ZmFrM2FoYzRiZHlkCiJAdVSSVgsksceIfHe41OJu9ZFHO8Kwv3G6F5OK3Hw4qZ6hn6SiZjtmJlJezoBH0voZlCahOU7jCOg+dsENndZxAA==
if gid, err := peer.ImportGroup(importString); err != nil {
if _, err := peer.ImportGroup(importString); err != nil {
return features.ConstructResponse(importBundlePrefix, err.Error())
} else {
// Auto accept the group here.
if peer.AcceptInvite(gid) != nil {
log.Errorf("Error accepting invite: %v", err)
}
return features.ConstructResponse(importBundlePrefix, "success")
}
return features.ConstructResponse(importBundlePrefix, "success")
}
return features.ConstructResponse(importBundlePrefix, "invalid_group_invite_prefix")
}

5
go.mod
View File

@ -3,8 +3,9 @@ module git.openprivacy.ca/flutter/libcwtch-go
go 1.15
require (
cwtch.im/cwtch v0.8.11
cwtch.im/cwtch v0.8.8
git.openprivacy.ca/openprivacy/connectivity v1.4.4
git.openprivacy.ca/openprivacy/log v1.0.2
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
golang.org/x/mobile v0.0.0-20210527171505-7e972142eb43 // indirect
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect
)

61
go.sum
View File

@ -1,13 +1,32 @@
cwtch.im/cwtch v0.8.11 h1:nUrd6srjLxInSJ0q1JdmRBhN4RRlZRL+2vIyE/AXkfY=
cwtch.im/cwtch v0.8.11/go.mod h1:D9dtO+WnKqdmufKSfFeFlUYaxLTfE/RtqVe1OD0kiKc=
cwtch.im/cwtch v0.8.2 h1:cn5utoZ7Od4iXiTthDn92XjXzXUEbcQGejCqrclI5yY=
cwtch.im/cwtch v0.8.2/go.mod h1:+SY/4ueF1U7mK+CX8hZFbtd+GC1lx/cReo110KgtQAw=
cwtch.im/cwtch v0.8.3 h1:HmMD+Lso5kZsYGZ6ak4nNkzIyPw1hFasw6BUglQgodA=
cwtch.im/cwtch v0.8.3/go.mod h1:+SY/4ueF1U7mK+CX8hZFbtd+GC1lx/cReo110KgtQAw=
cwtch.im/cwtch v0.8.5 h1:W67jAF2oRwqWytbZEv1UeCqW0cU2x69tgUw8iy27xFA=
cwtch.im/cwtch v0.8.5/go.mod h1:5GHxaaeVnKeXSU64IvtCKzkqhU8DRiLoVM+tiBT8kkc=
cwtch.im/cwtch v0.8.6 h1:V1cQIDlVijvwJAfQLMY0hbT8FsjrgkWm5ADITQR60qY=
cwtch.im/cwtch v0.8.6/go.mod h1:D9dtO+WnKqdmufKSfFeFlUYaxLTfE/RtqVe1OD0kiKc=
cwtch.im/cwtch v0.8.7 h1:SgXU4yvyhh+5pl2ITt2fQBAFcFk2ZHhxcs5PUmkJEL4=
cwtch.im/cwtch v0.8.7/go.mod h1:D9dtO+WnKqdmufKSfFeFlUYaxLTfE/RtqVe1OD0kiKc=
cwtch.im/cwtch v0.8.8 h1:NGe7HlScpCf5Me/35P9G+mo6dE5KgubVBfztGIEWxvc=
cwtch.im/cwtch v0.8.8/go.mod h1:D9dtO+WnKqdmufKSfFeFlUYaxLTfE/RtqVe1OD0kiKc=
git.openprivacy.ca/cwtch.im/tapir v0.4.1 h1:9LMpQX41IzecNNlRc1FZKXHg6wlFss679tFsa3vzb3Y=
git.openprivacy.ca/cwtch.im/tapir v0.4.1/go.mod h1:eH6dZxXrhW0C4KZX18ksUa6XJCrEvtg8cJJ/Fy6gv+E=
git.openprivacy.ca/cwtch.im/tapir v0.4.2 h1:bxMWZnVJXX4dqqOFS7ELW4iFkVL4GS8wiRkjRv5rJe8=
git.openprivacy.ca/cwtch.im/tapir v0.4.2/go.mod h1:eH6dZxXrhW0C4KZX18ksUa6XJCrEvtg8cJJ/Fy6gv+E=
git.openprivacy.ca/cwtch.im/tapir v0.4.3 h1:sctSfUXHDIqaHfJPDl+5lHtmoEJolQiHTcHZGAe5Qc4=
git.openprivacy.ca/cwtch.im/tapir v0.4.3/go.mod h1:10qEaib5x021zgyZ/97JKWsEpedH5+Vfy2CvB2V+08E=
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
git.openprivacy.ca/openprivacy/connectivity v1.4.3 h1:i2Ad/U9FlL9dKr2bhRck7lJ8NoWyGtoEfUwoCyMT0fU=
git.openprivacy.ca/openprivacy/connectivity v1.4.3/go.mod h1:bR0Myx9nm2YzWtsThRelkNMV4Pp7sPDa123O1qsAbVo=
git.openprivacy.ca/openprivacy/connectivity v1.4.4 h1:11M3akVCyy/luuhMpZTM1r9Jayl7IHD944Bxsn2FDpU=
git.openprivacy.ca/openprivacy/connectivity v1.4.4/go.mod h1:JVRCIdL+lAG6ohBFWiKeC/MN42nnC0sfFszR9XG6vPQ=
git.openprivacy.ca/openprivacy/log v1.0.1/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
git.openprivacy.ca/openprivacy/log v1.0.2 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -15,7 +34,9 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@ -25,46 +46,78 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/struCoder/pidusage v0.1.3 h1:pZcSa6asBE38TJtW0Nui6GeCjLTpaT/jAnNP7dUTLSQ=
github.com/struCoder/pidusage v0.1.3/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 h1:h+GZ3ubjuWaQjGe8owMGcmMVCqs0xYJtRG5y2bpHaqU=
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20210527171505-7e972142eb43 h1:YfX4EDYuRrJhCu1S8M+jsXVoQj+koh5ZIwpI7bzeQ38=
golang.org/x/mobile v0.0.0-20210527171505-7e972142eb43/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd h1:ePuNC7PZ6O5BzgPn9bZayERXBdfZjUYoXEf5BTfDfh8=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8=
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69 h1:yBHHx+XZqXJBm6Exke3N7V9gnlsyXxoCPEb1yVenjfk=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

282
lib.go
View File

@ -10,16 +10,16 @@ import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
"cwtch.im/cwtch/peer"
contact "git.openprivacy.ca/flutter/libcwtch-go/features/contacts"
"git.openprivacy.ca/flutter/libcwtch-go/features/groups"
"git.openprivacy.ca/openprivacy/connectivity"
"runtime"
"strings"
"encoding/json"
"fmt"
"git.openprivacy.ca/flutter/libcwtch-go/constants"
contact "git.openprivacy.ca/flutter/libcwtch-go/features/contacts"
"git.openprivacy.ca/flutter/libcwtch-go/features/groups"
"git.openprivacy.ca/flutter/libcwtch-go/utils"
"git.openprivacy.ca/openprivacy/connectivity"
"runtime"
"strconv"
"strings"
"encoding/base64"
"git.openprivacy.ca/openprivacy/connectivity/tor"
@ -58,22 +58,12 @@ type ChatMessage struct {
func c_StartCwtch(dir_c *C.char, len C.int, tor_c *C.char, torLen C.int) int8 {
dir := C.GoStringN(dir_c, len)
tor := C.GoStringN(tor_c, torLen)
return int8(StartCwtch(dir, tor))
return StartCwtch(dir, tor)
}
// StartCwtch starts cwtch in the library and initlaizes all data structures
// GetAppbusEvents is always safe to use
// the rest of functions are unsafe until the CwtchStarted event has been received indicating StartCwtch has completed
// returns:
// message: CwtchStarted when start up is complete and app is safe to use
// CwtchStartError message when start up fails (includes event.Error data field)
func StartCwtch(appDir string, torPath string) int {
func StartCwtch(appDir string, torPath string) int8 {
log.SetLevel(log.LevelInfo)
log.Infof("StartCwtch(...)")
// Quick hack check that we're being called with the correct params
// On android a stale worker could be calling us with "last apps" directory. Best to abort fast so the app can make a new worker
if runtime.GOOS == "android" {
fh, err := os.Open(torPath)
if err != nil {
@ -83,26 +73,13 @@ func StartCwtch(appDir string, torPath string) int {
}
_ = fh.Close()
}
go _startCwtch(appDir, torPath)
return 0
}
func _startCwtch(appDir string, torPath string) {
log.Infof("application: %v eventHandler: %v acn: %v", application, eventHandler, globalACN)
if application != nil {
log.Infof("_startCwtch detected existing application; resuming instead of relaunching")
ReconnectCwtchForeground()
return
}
// Exclude Tapir wire Messages
//(We need a TRACE level)
// Exclude Tapir wire Messages (We need a TRACE level)
log.ExcludeFromPattern("service.go")
// Ensure that the application directory exists...and then initialize settings..
os.MkdirAll(path.Join(appDir), 0700)
utils.InitGlobalSettingsFile(appDir, constants.DefactoPasswordForUnencryptedProfiles)
utils.InitGlobalSettingsFile(appDir, "be gay do crime")
log.Infof("Loading Cwtch Directory %v and tor path: %v", appDir, torPath)
@ -117,17 +94,14 @@ func _startCwtch(appDir string, torPath string) {
panic(err)
}
log.Infof("Creating new EventHandler()")
eventHandler = utils.NewEventHandler()
log.Infof("making directory %v", appDir)
os.MkdirAll(path.Join(appDir, "/.tor", "tor"), 0700)
tor.NewTorrc().WithSocksPort(port).WithOnionTrafficOnly().WithControlPort(controlPort).WithHashedPassword(base64.StdEncoding.EncodeToString(key)).Build(filepath.Join(appDir, ".tor", "tor", "torrc"))
acn, err := tor.NewTorACNWithAuth(path.Join(appDir, "/.tor"), torPath, controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)})
if err != nil {
log.Errorf("\nError connecting to Tor replacing with ErrorACN: %v\n", err)
eventHandler.PublishAppEvent(event.NewEventList(utils.CwtchStartError, event.Error, err))
return
// Replace the nil acn with a stub that will do nothing but report this error to the user...
acn = new(utils.ErrorACN)
}
globalACN = acn
newApp := app.NewApp(acn, appDir)
@ -137,7 +111,7 @@ func _startCwtch(appDir string, torPath string) {
newApp.GetPrimaryBus().Subscribe(utils.SetLoggingLevel, acnQueue)
newApp.GetPrimaryBus().Subscribe(event.AppError, acnQueue)
eventHandler.HandleApp(newApp)
eventHandler = utils.NewEventHandler(newApp)
peer.DefaultEventsToHandle = []event.Type{
event.EncryptedGroupMessage,
@ -157,14 +131,13 @@ func _startCwtch(appDir string, torPath string) {
settings := utils.ReadGlobalSettings()
settingsJson, _ := json.Marshal(settings)
newApp.LoadProfiles(constants.DefactoPasswordForUnencryptedProfiles)
newApp.LoadProfiles("be gay do crime")
application = newApp
// Send global settings to the UI...
application.GetPrimaryBus().Publish(event.NewEvent(utils.UpdateGlobalSettings, map[event.Field]string{event.Data: string(settingsJson)}))
log.Infof("libcwtch-go application launched")
application.GetPrimaryBus().Publish(event.NewEvent(utils.CwtchStarted, map[event.Field]string{}))
application.QueryACNVersion()
return 0
}
//export c_ReconnectCwtchForeground
@ -175,46 +148,24 @@ func c_ReconnectCwtchForeground() {
// Like StartCwtch, but StartCwtch has already been called so we don't need to restart Tor etc (probably)
// Do need to re-send initial state tho, eg profiles that are already loaded
func ReconnectCwtchForeground() {
log.Infof("Reconnecting cwtchforeground")
if application == nil {
log.Errorf("ReconnectCwtchForeground: Application is nil, presuming stale thread, EXITING Reconnect\n")
return
}
// populate profile list
peerList := application.ListPeers()
for onion := range peerList {
eventHandler.Push(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: onion, event.Created: event.False, "Reload": event.True}))
eventHandler.Push(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: onion, event.Created: event.False}))
}
}
for onion := range peerList {
// fix peerpeercontact message counts
contactList := application.GetPeer(onion).GetContacts()
for _, handle := range contactList {
totalMessages := application.GetPeer(onion).GetContact(handle).Timeline.Len() + len(application.GetPeer(onion).GetContact(handle).UnacknowledgedMessages)
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
event.Identity: onion,
event.RemotePeer: handle,
event.Data: strconv.Itoa(totalMessages),
}))
}
// fix peergroupcontact message counts
groupList := application.GetPeer(onion).GetGroups()
for _, groupID := range groupList {
totalMessages := application.GetPeer(onion).GetGroup(groupID).Timeline.Len() + len(application.GetPeer(onion).GetGroup(groupID).UnacknowledgedMessages)
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
event.Identity: onion,
event.GroupID: groupID,
event.Data: strconv.Itoa(totalMessages),
}))
}
//export c_ACNEvents
func c_ACNEvents() *C.char {
return C.CString(ACNEvents())
}
func ACNEvents() string {
select {
case myevent := <-acnQueue.OutChan():
return fmt.Sprintf("%v", myevent)
default:
return ""
}
application.GetPrimaryBus().Publish(event.NewEvent(utils.CwtchStarted, map[event.Field]string{}))
application.QueryACNStatus()
application.QueryACNVersion()
}
//export c_SendAppEvent
@ -347,38 +298,73 @@ func c_GetAppBusEvent() *C.char {
// GetAppBusEvent blocks until an event
func GetAppBusEvent() string {
log.Debugf("appbusevent called")
for eventHandler == nil {
log.Debugf("waiting for eventHandler != nil")
time.Sleep(time.Second)
}
var json = ""
for json == "" {
log.Debugf("waiting for json != ''")
json = eventHandler.GetNextEvent()
}
log.Debugf("appbusevent: %v", json)
return json
}
//export c_GetProfileRepaintEvent
func c_GetProfileRepaintEvent() int8 {
if GetProfileRepaintEvent() {
return 1
} else {
return 0
}
}
func GetProfileRepaintEvent() bool {
<-acnQueue.OutChan()
return true
}
type Profile struct {
Name string `json:"name"`
Onion string `json:"onion"`
ImagePath string `json:"imagePath"`
}
//export c_GetProfiles
func c_GetProfiles() *C.char {
return C.CString(GetProfiles())
}
func GetProfiles() string {
peerList := application.ListPeers()
profiles := make([]Profile, len(peerList))
i := 0
for onion := range peerList {
name, _ := application.GetPeer(onion).GetAttribute(attr.GetPublicScope(constants.Name))
profiles[i] = Profile{
Name: name,
Onion: onion,
ImagePath: "",
}
i += 1
}
jsonBytes, _ := json.Marshal(profiles)
return string(jsonBytes)
}
//export c_CreateProfile
func c_CreateProfile(nick_ptr *C.char, nick_len C.int, pass_ptr *C.char, pass_len C.int) {
CreateProfile(C.GoStringN(nick_ptr, nick_len), C.GoStringN(pass_ptr, pass_len))
}
func CreateProfile(nick, pass string) {
if pass == constants.DefactoPasswordForUnencryptedProfiles {
application.CreateTaggedPeer(nick, pass, constants.ProfileTypeV1DefaultPassword)
} else {
application.CreateTaggedPeer(nick, pass, constants.ProfileTypeV1Password)
}
application.CreatePeer(nick, pass)
}
//export c_SelectProfile
func c_SelectProfile(onion_ptr *C.char, onion_len C.int) *C.char {
return C.CString(SelectProfile(C.GoStringN(onion_ptr, onion_len)))
}
func SelectProfile(onion string) string {
contactEventsQueue = event.NewQueue()
application.GetEventBus(onion).Subscribe(event.PeerStateChange, contactEventsQueue)
return ""
}
//export c_LoadProfiles
@ -464,6 +450,36 @@ func BlockContact(profile, handle string) {
}
}
//export c_DebugResetContact
func c_DebugResetContact(profilePtr *C.char, profileLen C.int, handlePtr *C.char, handleLen C.int) {
DebugResetContact(C.GoStringN(profilePtr, profileLen), C.GoStringN(handlePtr, handleLen))
}
func DebugResetContact(profile, handle string) {
err := application.GetPeer(profile).SetContactAuthorization(handle, model.AuthUnknown)
if err == nil {
application.GetPrimaryBus().Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{
ProfileOnion: profile,
event.RemotePeer: handle,
"authorization": string(model.AuthUnknown),
}))
} else {
log.Errorf("error resetting contact: %s", err.Error())
}
}
//export c_NumMessages
func c_NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n int) {
profile := C.GoStringN(profile_ptr, profile_len)
handle := C.GoStringN(handle_ptr, handle_len)
return (NumMessages(profile, handle))
}
func NumMessages(profile, handle string) (n int) {
n = len(application.GetPeer(profile).GetContact(handle).Timeline.Messages)
return
}
//export c_UpdateMessageFlags
func c_UpdateMessageFlags(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, mIdx C.int, message_flags C.ulong) {
profile := C.GoStringN(profile_ptr, profile_len)
@ -471,6 +487,7 @@ func c_UpdateMessageFlags(profile_ptr *C.char, profile_len C.int, handle_ptr *C.
UpdateMessageFlags(profile, handle, int(mIdx), int64(message_flags))
}
// UpdateMessageFlags sets the messages flags on a given message for a given profile.
// gomobile doesn't support uint64...so here we are....
func UpdateMessageFlags(profileOnion, handle string, mIdx int, flags int64) {
@ -519,19 +536,24 @@ func GetMessage(profileOnion, handle string, message_index int) string {
if message_index < len(profile.GetContact(handle).Timeline.Messages) {
message.Message = profile.GetContact(handle).Timeline.Messages[message_index]
message.ContactImage = ph.GetProfilePic(handle)
} else {
log.Errorf("peerpeercontact getmessage out of range; sending counter resync just in case")
eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{
event.Identity: profileOnion,
event.RemotePeer: handle,
event.Data: strconv.Itoa(len(profile.GetContact(handle).Timeline.Messages)),
}))
}
}
bytes, _ := json.Marshal(message)
return string(bytes)
}
//export c_GetMessages
func c_GetMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, start C.int, end C.int) *C.char {
profile := C.GoStringN(profile_ptr, profile_len)
handle := C.GoStringN(handle_ptr, handle_len)
return C.CString(GetMessages(profile, handle, int(start), int(end)))
}
func GetMessages(profile, handle string, start, end int) string {
messages := application.GetPeer(profile).GetContact(handle).Timeline.Messages[start:end]
bytes, _ := json.Marshal(messages)
return string(bytes)
}
//export c_SendMessage
func c_SendMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, msg_ptr *C.char, msg_len C.int) {
@ -598,6 +620,15 @@ func ResetTor() {
globalACN.Restart()
}
//export c_QueryACNVersion
func c_QueryACNVersion() {
QueryACNVersion()
}
func QueryACNVersion() {
application.QueryACNVersion()
}
//export c_CreateGroup
func c_CreateGroup(profile_ptr *C.char, profile_len C.int, server_ptr *C.char, server_len C.int, name_ptr *C.char, name_len C.int) {
profile := C.GoStringN(profile_ptr, profile_len)
@ -622,37 +653,6 @@ func CreateGroup(profile string, server string, name string) {
}
}
//export c_DeleteProfile
func c_DeleteProfile(profile_ptr *C.char, profile_len C.int, password_ptr *C.char, password_len C.int) {
profile := C.GoStringN(profile_ptr, profile_len)
password := C.GoStringN(password_ptr, password_len)
DeleteProfile(profile, password)
}
// DeleteProfile deletes a profile given the right password
func DeleteProfile(profile string, password string) {
// allow a blank password to delete "unencrypted" accounts...
if password == "" {
password = constants.DefactoPasswordForUnencryptedProfiles
}
application.DeletePeer(profile, password)
}
//export c_LeaveConversation
func c_LeaveConversation(profile_ptr *C.char, profile_len C.int, contact_ptr *C.char, contact_len C.int) {
profile := C.GoStringN(profile_ptr, profile_len)
contact := C.GoStringN(contact_ptr, contact_len)
LeaveConversation(profile, contact)
}
// LeaveConversation forces profile to leave the peer
func LeaveConversation(profile string, contact string) {
peer := application.GetPeer(profile)
peer.DeleteContact(contact)
}
//export c_LeaveGroup
func c_LeaveGroup(profile_ptr *C.char, profile_len C.int, group_ptr *C.char, group_len C.int) {
profile := C.GoStringN(profile_ptr, profile_len)
@ -692,7 +692,7 @@ func ImportBundle(profileOnion string, bundle string) {
serverListForOnion := groupHandler.GetServerInfoList(profile)
serversListBytes, _ := json.Marshal(serverListForOnion)
eventHandler.Push(event.NewEvent(groups.UpdateServerInfo, map[event.Field]string{"ProfileOnion": profileOnion, groups.ServerList: string(serversListBytes)}))
return
}
}
eventHandler.Push(event.NewEvent(event.AppError, map[event.Field]string{event.Data: response.Error()}))
@ -716,29 +716,5 @@ func SetGroupAttribute(profileOnion string, groupHandle string, key string, valu
}
}
//export c_ShutdownCwtch
func c_ShutdownCwtch() {
ShutdownCwtch()
}
// ShutdownCwtch is a safe way to shutdown any active cwtch applications and associated ACNs
func ShutdownCwtch() {
if application != nil && globalACN != nil {
// Kill the isolate
eventHandler.Push(event.NewEvent(event.Shutdown, map[event.Field]string{}))
// Allow for the shutdown events to go through and then purge everything else...
log.Infof("Shutting Down Application...")
application.Shutdown()
log.Infof("Shutting Down ACN...")
globalACN.Close()
log.Infof("Library Shutdown Complete!")
// do not remove - important for state checks elsewhere
application = nil
globalACN = nil
eventHandler = nil
}
}
// Leave as is, needed by ffi
func main() {}

54
utils/errorACN.go Normal file
View File

@ -0,0 +1,54 @@
package utils
import (
"errors"
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/log"
"net"
)
// ErrorACN is a stub ACN handler used when no other valid ACN can be found. This is a critical error and as such
// this is only used when the only course of action is to close Cwtch and fix the underlying discovery problem...
type ErrorACN struct {
}
func (e ErrorACN) GetBootstrapStatus() (int, string) {
return -1, "could not find tor"
}
func (e ErrorACN) WaitTillBootstrapped() {
// instant
}
func (e ErrorACN) SetStatusCallback(callback func(int, string)) {
callback(-1, "could not find tor please restart cwtch with an active Tor in path")
}
func (e ErrorACN) Restart() {
// does nothing
log.Errorf("Called Restart() on ErrorACN, which does nothing")
}
func (e ErrorACN) Open(hostname string) (net.Conn, string, error) {
return nil,"", errors.New("could not find tor")
}
func (e ErrorACN) Listen(identity connectivity.PrivateKey, port int) (connectivity.ListenService, error) {
return nil, errors.New("could not find tor")
}
func (e ErrorACN) GetPID() (int, error) {
return 0, errors.New("could not find tor")
}
func (e ErrorACN) GetVersion() string {
return "could not find tor"
}
func (e ErrorACN) Close() {
// does nothing
}

View File

@ -23,31 +23,20 @@ type EventHandler struct {
app app.Application
appBusQueue event.Queue
profileEvents chan EventProfileEnvelope
profileQueues map[string]event.Queue
}
func NewEventHandler() *EventHandler {
eh := &EventHandler{app: nil, appBusQueue: event.NewQueue(), profileEvents: make(chan EventProfileEnvelope)}
return eh
}
// PublishAppEvent is a way for libCwtch-go to publish an event for consumption by a UI before a Cwtch app has been initialized
// Main use: to signal an error before a cwtch app could be created
func (eh *EventHandler) PublishAppEvent(event event.Event) {
eh.appBusQueue.Publish(event)
}
func (eh *EventHandler) HandleApp(application app.Application) {
eh.app = application
application.GetPrimaryBus().Subscribe(event.NewPeer, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.PeerError, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.PeerDeleted, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.Shutdown, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.AppError, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.ACNStatus, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.ReloadDone, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.ACNVersion, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(UpdateGlobalSettings, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(CwtchStarted, eh.appBusQueue)
func NewEventHandler(application app.Application) *EventHandler {
appBusQueue := event.NewQueue()
application.GetPrimaryBus().Subscribe(event.NewPeer, appBusQueue)
application.GetPrimaryBus().Subscribe(event.PeerError, appBusQueue)
application.GetPrimaryBus().Subscribe(event.AppError, appBusQueue)
application.GetPrimaryBus().Subscribe(event.ACNStatus, appBusQueue)
application.GetPrimaryBus().Subscribe(event.ReloadDone, appBusQueue)
application.GetPrimaryBus().Subscribe(event.ACNVersion, appBusQueue)
application.GetPrimaryBus().Subscribe(UpdateGlobalSettings, appBusQueue)
return &EventHandler{app: application, appBusQueue: appBusQueue, profileQueues: make(map[string]event.Queue), profileEvents: make(chan EventProfileEnvelope)}
}
func (eh *EventHandler) GetNextEvent() string {
@ -64,163 +53,149 @@ func (eh *EventHandler) GetNextEvent() string {
// handleAppBusEvent enriches AppBus events so they are usable with out further data fetches
func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
log.Debugf("New AppBus Event to Handle: %v", e)
if eh.app != nil {
switch e.EventType {
case event.ACNStatus:
if e.Data[event.Progress] == "100" {
for onion := range eh.app.ListPeers() {
// launch a listen thread (internally this does a check that the protocol engine is not listening)
// and as such is safe to call.
eh.app.GetPeer(onion).Listen()
}
switch e.EventType {
case event.ACNStatus:
if e.Data[event.Progress] == "100" {
for onion := range eh.app.ListPeers() {
// launch a listen thread (internally this does a check that the protocol engine is not listening)
// and as such is safe to call.
eh.app.GetPeer(onion).Listen()
}
case event.NewPeer:
onion := e.Data[event.Identity]
profile := eh.app.GetPeer(e.Data[event.Identity])
log.Debug("New Peer Event: %v", e)
if e.Data["Reload"] != event.True {
eh.startHandlingPeer(onion)
}
tag,isTagged := profile.GetAttribute(app.AttributeTag)
if isTagged {
e.Data[app.AttributeTag] = tag
} else {
// Assume encrypted for non-tagged profiles - this isn't always true, but all post-beta profiles
// are tagged on creation.
e.Data[app.AttributeTag] = constants.ProfileTypeV1Password
}
if e.Data[event.Created] == event.True {
name, _ := profile.GetAttribute(attr.GetLocalScope(constants.Name))
profile.SetAttribute(attr.GetPublicScope(constants.Name), name)
profile.SetAttribute(attr.GetPublicScope(constants.Picture), ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
}
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
// If the user has chosen to block unknown profiles
// then explicitly configure the protocol engine to do so..
if ReadGlobalSettings().BlockUnknownConnections {
profile.BlockUnknownConnections()
} else {
// For completeness
profile.AllowUnknownConnections()
}
// Start up the Profile
profile.Listen()
profile.StartPeersConnections()
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
profile.StartServerConnections()
}
}
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
if !exists {
nick = onion
}
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
if !ok {
picVal = ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))
}
pic, err := StringToImage(picVal)
if err != nil {
pic = NewImage(RandomProfileImage(onion), TypeImageDistro)
}
picPath := GetPicturePath(pic)
//tag, _ := profile.GetAttribute(app.AttributeTag)
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
e.Data[constants.Name] = nick
e.Data[constants.Picture] = picPath
e.Data["Online"] = online
var contacts []Contact
var servers []groups.Server
for _, contact := range profile.GetContacts() {
// Only compile the server info if we have enabled the experiment...
// Note that this means that this info can become stale if when first loaded the experiment
// has been disabled and then is later re-enabled. As such we need to ensure that this list is
// re-fetched when the group experiment is enabled via a dedicated ListServerInfo event...
if profile.GetContact(contact).IsServer() {
groupHandler, err := groups.ExperimentGate(ReadGlobalSettings().Experiments)
if err == nil {
servers = append(servers, groupHandler.GetServerInfo(contact, profile))
}
continue
}
contactInfo := profile.GetContact(contact)
ph := NewPeerHelper(profile)
name := ph.GetNick(contact)
cpicPath := ph.GetProfilePic(contact)
saveHistory, set := contactInfo.GetAttribute(event.SaveHistoryKey)
if !set {
saveHistory = event.DeleteHistoryDefault
}
contacts = append(contacts, Contact{
Name: name,
Onion: contactInfo.Onion,
Status: contactInfo.State,
Picture: cpicPath,
Authorization: string(contactInfo.Authorization),
SaveHistory: saveHistory,
Messages: contactInfo.Timeline.Len(),
Unread: 0,
LastMessage: strconv.Itoa(getLastMessageTime(&contactInfo.Timeline)),
IsGroup: false,
})
}
// We compile and send the groups regardless of the experiment flag, and hide them in the UI
for _, groupId := range profile.GetGroups() {
group := profile.GetGroup(groupId)
// Check that the group is cryptographically valid
if !group.CheckGroup() {
continue
}
ph := NewPeerHelper(profile)
cpicPath := ph.GetProfilePic(groupId)
authorization := model.AuthUnknown
if group.Accepted {
authorization = model.AuthApproved
}
contacts = append(contacts, Contact{
Name: ph.GetNick(groupId),
Onion: group.GroupID,
Status: group.State,
Picture: cpicPath,
Authorization: string(authorization),
SaveHistory: event.SaveHistoryConfirmed,
Messages: group.Timeline.Len(),
Unread: 0,
LastMessage: strconv.Itoa(getLastMessageTime(&group.Timeline)),
IsGroup: true,
GroupServer: group.GroupServer,
})
}
bytes, _ := json.Marshal(contacts)
e.Data["ContactsJson"] = string(bytes)
// Marshal the server list into the new peer event...
serversListBytes, _ := json.Marshal(servers)
e.Data[groups.ServerList] = string(serversListBytes)
log.Debugf("contactsJson %v", e.Data["ContactsJson"])
}
case event.NewPeer:
onion := e.Data[event.Identity]
profile := eh.app.GetPeer(e.Data[event.Identity])
log.Debug("New Peer Event: %v", e)
eh.startHandlingPeer(onion)
if e.Data[event.Created] == event.True {
name, _ := profile.GetAttribute(attr.GetLocalScope(constants.Name))
profile.SetAttribute(attr.GetPublicScope(constants.Name), name)
profile.SetAttribute(attr.GetPublicScope(constants.Picture), ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
}
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
// If the user has chosen to block unknown profiles
// then explicitly configure the protocol engine to do so..
if ReadGlobalSettings().BlockUnknownConnections {
profile.BlockUnknownConnections()
} else {
// For completeness
profile.AllowUnknownConnections()
}
// Start up the Profile
profile.Listen()
profile.StartPeersConnections()
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
profile.StartServerConnections()
}
}
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
if !exists {
nick = onion
}
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
if !ok {
picVal = ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))
}
pic, err := StringToImage(picVal)
if err != nil {
pic = NewImage(RandomProfileImage(onion), TypeImageDistro)
}
picPath := GetPicturePath(pic)
//tag, _ := profile.GetAttribute(app.AttributeTag)
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
e.Data[constants.Name] = nick
e.Data[constants.Picture] = picPath
e.Data["Online"] = online
var contacts []Contact
var servers []groups.Server
for _, contact := range profile.GetContacts() {
// Only compile the server info if we have enabled the experiment...
// Note that this means that this info can become stale if when first loaded the experiment
// has been disabled and then is later re-enabled. As such we need to ensure that this list is
// re-fetched when the group experiment is enabled via a dedicated ListServerInfo event...
if profile.GetContact(contact).IsServer() {
groupHandler, err := groups.ExperimentGate(ReadGlobalSettings().Experiments)
if err == nil {
servers = append(servers, groupHandler.GetServerInfo(contact, profile))
}
continue
}
contactInfo := profile.GetContact(contact)
ph := NewPeerHelper(profile)
name := ph.GetNick(contact)
cpicPath := ph.GetProfilePic(contact)
saveHistory, set := contactInfo.GetAttribute(event.SaveHistoryKey)
if !set {
saveHistory = event.DeleteHistoryDefault
}
contacts = append(contacts, Contact{
Name: name,
Onion: contactInfo.Onion,
Status: contactInfo.State,
Picture: cpicPath,
Authorization: string(contactInfo.Authorization),
SaveHistory: saveHistory,
Messages: contactInfo.Timeline.Len(),
Unread: 0,
LastMessage: strconv.Itoa(getLastMessageTime(&contactInfo.Timeline)),
IsGroup: false,
})
}
// We compile and send the groups regardless of the experiment flag, and hide them in the UI
for _, groupId := range profile.GetGroups() {
group := profile.GetGroup(groupId)
// Check that the group is cryptographically valid
if !group.CheckGroup() {
continue
}
ph := NewPeerHelper(profile)
cpicPath := ph.GetProfilePic(groupId)
authorization := model.AuthUnknown
if group.Accepted {
authorization = model.AuthApproved
}
contacts = append(contacts, Contact{
Name: ph.GetNick(groupId),
Onion: group.GroupID,
Status: group.State,
Picture: cpicPath,
Authorization: string(authorization),
SaveHistory: event.SaveHistoryConfirmed,
Messages: group.Timeline.Len(),
Unread: 0,
LastMessage: strconv.Itoa(getLastMessageTime(&group.Timeline)),
IsGroup: true,
GroupServer: group.GroupServer,
})
}
bytes, _ := json.Marshal(contacts)
e.Data["ContactsJson"] = string(bytes)
// Marshal the server list into the new peer event...
serversListBytes, _ := json.Marshal(servers)
e.Data[groups.ServerList] = string(serversListBytes)
log.Infof("contactsJson %v", e.Data["ContactsJson"])
}
json, _ := json.Marshal(e)
@ -229,96 +204,131 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
// handleProfileEvent enriches Profile events so they are usable with out further data fetches
func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
if eh.app == nil {
log.Errorf("eh.app == nil in handleProfileEvent... this shouldnt happen?")
} else {
peer := eh.app.GetPeer(ev.Profile)
ph := NewPeerHelper(peer)
log.Debugf("New Profile Event to Handle: %v", ev)
switch ev.Event.EventType {
/*
TODO: still handle this somewhere - network info from plugin Network check
case event.NetworkStatus:
online, _ := peer.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
if e.Data[event.Status] == plugins.NetworkCheckSuccess && online == event.False {
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.True)
uiManager.UpdateNetworkStatus(true)
// TODO we may have to reinitialize the peer
} else if e.Data[event.Status] == plugins.NetworkCheckError && online == event.True {
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
uiManager.UpdateNetworkStatus(false)
}*/
peer := eh.app.GetPeer(ev.Profile)
ph := NewPeerHelper(peer)
log.Debugf("New Profile Event to Handle: %v", ev)
switch ev.Event.EventType {
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
// only needs contact nickname and picture, for displaying on popup notifications
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data["RemotePeer"])
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data["RemotePeer"])
case event.NewMessageFromGroup:
// only needs contact nickname and picture, for displaying on popup notifications
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data[event.GroupID])
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data[event.GroupID])
case event.PeerAcknowledgement:
// No enrichement required
case event.PeerCreated:
handle := ev.Event.Data[event.RemotePeer]
err := EnrichNewPeer(handle, ph, ev)
if err != nil {
return ""
/*case event.NetworkStatus:
online, _ := peer.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
if e.Data[event.Status] == plugins.NetworkCheckSuccess && online == event.False {
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.True)
uiManager.UpdateNetworkStatus(true)
// TODO we may have to reinitialize the peer
} else if e.Data[event.Status] == plugins.NetworkCheckError && online == event.True {
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
uiManager.UpdateNetworkStatus(false)
}*/
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
// only needs contact nickname and picture, for displaying on popup notifications
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data["RemotePeer"])
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data["RemotePeer"])
case event.PeerAcknowledgement:
// No enrichement required
//Acknowledge(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.EventID])
/*
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), hex.EncodeToString([]byte(e.Data[event.Signature])), ts, true)
case event.NewGroupInvite:
gid, err := peer.ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
group := peer.GetGroup(gid)
if err == nil && group != nil {
uiManager.AddContact(gid)
}
case event.GroupCreated:
// This event should only happen after we have validated the invite, as such the error
// condition *should* never happen.
*/
case event.PeerCreated:
handle := ev.Event.Data[event.RemotePeer]
err := EnrichNewPeer(handle, ph, ev)
if err != nil {
return ""
}
/*
case event.SendMessageToGroupError:
uiManager.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error])
case event.SendMessageToPeerError:
uiManager.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.EventID], e.Data[event.Error])
*/
case event.GroupCreated:
// This event should only happen after we have validated the invite, as such the error
// condition *should* never happen.
groupPic := ph.GetProfilePic(ev.Event.Data[event.GroupID])
groupPic := ph.GetProfilePic(ev.Event.Data[event.GroupID])
ev.Event.Data["PicturePath"] = groupPic
ev.Event.Data["GroupName"] = ph.GetNick(ev.Event.Data[event.GroupID])
case event.NewGroup:
// This event should only happen after we have validated the invite, as such the error
// condition *should* never happen.
serializedInvite := ev.Event.Data[event.GroupInvite]
if invite, err := model.ValidateInvite(serializedInvite); err == nil {
groupPic := ph.GetProfilePic(invite.GroupID)
ev.Event.Data["PicturePath"] = groupPic
ev.Event.Data["GroupName"] = ph.GetNick(ev.Event.Data[event.GroupID])
} else {
log.Errorf("received a new group event which contained an invalid invite %v. this should never happen and likely means there is a bug in cwtch. Please file a ticket @ https://git.openprivcy.ca/cwtch.im/cwtch", err)
return ""
}
case event.PeerStateChange:
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
contact := peer.GetContact(ev.Event.Data[event.RemotePeer])
case event.NewGroup:
// This event should only happen after we have validated the invite, as such the error
// condition *should* never happen.
serializedInvite := ev.Event.Data[event.GroupInvite]
if invite, err := model.ValidateInvite(serializedInvite); err == nil {
groupPic := ph.GetProfilePic(invite.GroupID)
ev.Event.Data["PicturePath"] = groupPic
} else {
log.Errorf("received a new group event which contained an invalid invite %v. this should never happen and likely means there is a bug in cwtch. Please file a ticket @ https://git.openprivcy.ca/cwtch.im/cwtch", err)
return ""
}
case event.PeerStateChange:
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
contact := peer.GetContact(ev.Event.Data[event.RemotePeer])
if cxnState == connections.AUTHENTICATED && contact == nil {
peer.AddContact(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.RemotePeer], model.AuthUnknown)
return ""
}
if cxnState == connections.AUTHENTICATED && contact == nil {
peer.AddContact(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.RemotePeer], model.AuthUnknown)
return ""
}
if contact != nil {
// No enrichment needed
//uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
if cxnState == connections.AUTHENTICATED {
// if known and authed, get vars
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Name)
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Picture)
}
}
case event.NewRetValMessageFromPeer:
// auto handled event means the setting is already done, we're just deciding if we need to tell the UI
onion := ev.Event.Data[event.RemotePeer]
scope := ev.Event.Data[event.Scope]
path := ev.Event.Data[event.Path]
//val := ev.Event.Data[event.Data]
exists, _ := strconv.ParseBool(ev.Event.Data[event.Exists])
if exists && scope == attr.PublicScope {
if _, exists := peer.GetContactAttribute(onion, attr.GetLocalScope(path)); exists {
// we have a locally set ovverride, don't pass this remote set public scope update to UI
return ""
}
if contact != nil {
// No enrichment needed
//uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
if cxnState == connections.AUTHENTICATED {
// if known and authed, get vars
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Name)
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Picture)
}
}
/*case event.NewRetValMessageFromPeer:
onion := e.Data[event.RemotePeer]
scope := e.Data[event.Scope]
path := e.Data[event.Path]
val := e.Data[event.Data]
exists, _ := strconv.ParseBool(e.Data[event.Exists])
if exists && scope == attr.PublicScope {
switch path {
case constants.Name:
peer.SetContactAttribute(onion, attr.GetPeerScope(constants.Name), val)
uiManager.UpdateContactDisplayName(onion)
case constants.Picture:
peer.SetContactAttribute(onion, attr.GetPeerScope(constants.Picture), val)
uiManager.UpdateContactPicture(onion)
}
}
case event.ServerStateChange:
serverOnion := e.Data[event.GroupServer]
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
groups := peer.GetGroups()
for _, groupID := range groups {
group := peer.GetGroup(groupID)
if group != nil && group.GroupServer == serverOnion {
group.State = e.Data[event.ConnectionState]
loading := false
if state == connections.AUTHENTICATED {
loading = true
}
uiManager.UpdateContactStatus(groupID, int(state), loading)
uiManager.UpdateContactStatus(serverOnion, int(state), loading)
}
}
case event.DeletePeer:
log.Infof("PeerHandler got DeletePeer, SHUTTING down!\n")
uiManager.ReloadProfiles()
return
*/
}
json, _ := json.Marshal(unwrap(ev))
@ -336,8 +346,6 @@ func (eh *EventHandler) startHandlingPeer(onion string) {
q := event.NewQueue()
eventBus.Subscribe(event.NewMessageFromPeer, q)
eventBus.Subscribe(event.PeerAcknowledgement, q)
eventBus.Subscribe(event.DeleteContact, q)
eventBus.Subscribe(event.AppError, q)
eventBus.Subscribe(event.IndexedAcknowledgement, q)
eventBus.Subscribe(event.IndexedFailure, q)
eventBus.Subscribe(event.NewMessageFromGroup, q)
@ -356,21 +364,18 @@ func (eh *EventHandler) startHandlingPeer(onion string) {
eventBus.Subscribe(event.ChangePasswordError, q)
eventBus.Subscribe(event.NewRetValMessageFromPeer, q)
eventBus.Subscribe(event.SetAttribute, q)
eh.profileQueues[onion] = q
go eh.forwardProfileMessages(onion, q)
}
func (eh *EventHandler) forwardProfileMessages(onion string, q event.Queue) {
log.Infof("Launching Forwarding Goroutine for %v", onion)
// TODO: graceful shutdown, via an injected event of special QUIT type exiting loop/go routine
for {
e := q.Next()
ev := EventProfileEnvelope{Event: e, Profile: onion}
eh.profileEvents <- ev
if ev.Event.EventType == event.Shutdown {
return
}
}
}

View File

@ -87,8 +87,6 @@ func (p *PeerHelper) GetNick(id string) string {
nick, exists = p.peer.GetContactAttribute(id, attr.GetPeerScope(constants.Name))
if !exists {
nick = "[" + id + "]"
// re-request
p.peer.SendGetValToPeer(id, attr.PublicScope, constants.Name)
}
}
return nick
@ -286,7 +284,7 @@ func EnrichNewPeer(handle string, ph *PeerHelper, ev *EventProfileEnvelope) erro
}
} else {
// could be a server?
log.Debugf("sorry, unable to handle AddContact(%v)", handle)
log.Infof("sorry, unable to handle AddContact(%v)", handle)
return errors.New("not a peer or group")
}
return nil

View File

@ -12,8 +12,6 @@ import (
)
const (
CwtchStarted = event.Type("CwtchStarted")
CwtchStartError = event.Type("CwtchStartError")
UpdateGlobalSettings = event.Type("UpdateGlobalSettings")
)
@ -31,8 +29,6 @@ type GlobalSettings struct {
BlockUnknownConnections bool
StateRootPane int
FirstTime bool
UIColumnModePortrait string
UIColumnModeLandscape string
}
var DefaultGlobalSettings = GlobalSettings{
@ -44,8 +40,6 @@ var DefaultGlobalSettings = GlobalSettings{
StateRootPane: 0,
FirstTime: true,
BlockUnknownConnections: false,
UIColumnModePortrait: "DualpaneMode.Single",
UIColumnModeLandscape: "DualpaneMode.CopyPortrait",
}
func InitGlobalSettingsFile(directory string, password string) error {