forked from aksdb/CalAnonSync
Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Andreas Schneider | 73a7754742 | |
Andreas Schneider | 8d8cc94213 | |
Andreas Schneider | 4d93b99cad | |
Andreas Schneider | 10b96ec705 | |
Andreas Schneider | cf04126d27 |
26
README.md
26
README.md
|
@ -41,7 +41,12 @@ A config file named `calanonsync.json` is opened from the working directory. It
|
|||
"Password": ""
|
||||
},
|
||||
"Anonymize": {
|
||||
"Title": "#Work"
|
||||
"Title": {
|
||||
"ReplaceWith": "#Work",
|
||||
"Whitelist": [
|
||||
"Something"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -49,3 +54,22 @@ A config file named `calanonsync.json` is opened from the working directory. It
|
|||
Both passwords are optional. If they are left blank, CalAnonSync will prompt for the password upon startup. (Recommended for security reasons!)
|
||||
|
||||
The CalDAV URL should point to the URL of a dedicated calendar. Beware that CalAnonSync will remove **all** events from that calendar that are not known to Exchange.
|
||||
|
||||
### Whitelist
|
||||
|
||||
If words (or phrases) are whitelisted, matches within the title for these words (or phrases) will be used as the
|
||||
new title instead of the replacement. The order of these matches within the original title is kept, all non matching
|
||||
parts of the title are simply stripped.
|
||||
|
||||
### Encryption
|
||||
|
||||
If you want to automate the sync process your probably have not much of a choice but storing the passwords
|
||||
in the config file. Since plaintext passwords are always a big risk, CalAnonSync at least provides a simple
|
||||
layer of eavesdropping security.
|
||||
|
||||
Using `calanonsync settings encrypt` you can encrypt all passwords in the config file. With `calanonsync settings decrypt`
|
||||
you can revert that process.
|
||||
|
||||
Beware, that the encryption key is simply stored in a file alongside the config so it is really easy to decrypt.
|
||||
It doesn't provide any security against a real attack and is only meant to prevent someone from getting access
|
||||
to the password by looking over your shoulder.
|
||||
|
|
22
build.go
22
build.go
|
@ -3,23 +3,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var reproducible = flag.Bool("r", false, "If set, the build will remove local directories from the debug infos.")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
env := os.Environ()
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
env = append(env, "GOPATH="+wd)
|
||||
|
||||
args := []string{"build"}
|
||||
env = append(env, "GOPATH="+wd, "CGO_ENABLED=0")
|
||||
|
||||
if len(os.Args) == 2 {
|
||||
target := os.Args[1]
|
||||
args := []string{"build", "-ldflags=-s -w"}
|
||||
|
||||
if *reproducible {
|
||||
args = append(args,
|
||||
"-asmflags=all=-trimpath="+wd,
|
||||
"-gcflags=all=-trimpath="+wd,
|
||||
"-a",
|
||||
)
|
||||
}
|
||||
|
||||
if len(flag.Args()) == 1 {
|
||||
target := flag.Arg(0)
|
||||
targetParts := strings.Split(target, "/")
|
||||
if len(targetParts) != 2 {
|
||||
println("Invalid target specification. Example: windows/386")
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/ThomsonReutersEikon/go-ntlm"
|
||||
packages = [
|
||||
"ntlm",
|
||||
"ntlm/md4"
|
||||
]
|
||||
revision = "2a7c173f9e18233a4ae29891da6a0a63637e2d8d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
|
@ -28,12 +19,6 @@
|
|||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/vadimi/go-http-ntlm"
|
||||
packages = ["."]
|
||||
revision = "bc5a8d8d91a12dd386d3fa1019abb8bb681bdd41"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
@ -52,6 +37,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "8a1421bb063ff7faff2c4276042f954d7965c60c6a51afc95b658ac721cfcea0"
|
||||
inputs-digest = "d2f5b5a67e95e173cd0d93a24576cdc1e5384e2bc0246f8cbed88838514b8ec0"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
ignored = ["github.com/vadimi/go-http-ntlm"]
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
|
@ -33,14 +34,6 @@
|
|||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/vadimi/go-http-ntlm"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/Azure/go-ntlmssp"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "0.0.2"
|
||||
|
|
|
@ -8,12 +8,17 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var syncSettings = struct {
|
||||
rebuild bool
|
||||
}{}
|
||||
|
||||
func main() {
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "calanonsync",
|
||||
Short: "Synchronize a calendar from EWS to CalDAV by event time and an anonymized title only.",
|
||||
Run: runSynchronization,
|
||||
}
|
||||
rootCmd.Flags().BoolVar(&syncSettings.rebuild, "rebuild", false, "Rebuild all calendar items, no matter if they already exist.")
|
||||
|
||||
rootCmd.AddCommand(InitSettingsCmd())
|
||||
|
||||
|
@ -66,6 +71,13 @@ func runSynchronization(cmd *cobra.Command, args []string) {
|
|||
for uid, calDavItem := range calDavItemMap {
|
||||
if ewsItem, ok := relevantEWSItems[uid]; ok {
|
||||
// Good, so we still know the item at least.
|
||||
|
||||
// If we want a full rebuild, we can skip this step
|
||||
// since we will create new items anyway.
|
||||
if syncSettings.rebuild {
|
||||
continue
|
||||
}
|
||||
|
||||
if !ewsItem.Start.Equal(calDavItem.Start()) ||
|
||||
!ewsItem.End.Equal(calDavItem.End()) {
|
||||
|
||||
|
@ -92,9 +104,9 @@ func runSynchronization(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
}
|
||||
|
||||
// Find items we don't know so far and create them.
|
||||
// Find items we don't know so far and create them. Also recreate them if we want to rebuild all.
|
||||
for uid, ewsItem := range relevantEWSItems {
|
||||
if _, ok := calDavItemMap[uid]; !ok {
|
||||
if _, ok := calDavItemMap[uid]; !ok || syncSettings.rebuild {
|
||||
title := s.Anonymize.Title.Apply(ewsItem.Subject)
|
||||
ical := CreateICal(ewsItem.Hash(), title, ewsItem.Start, ewsItem.End, ewsItem.IsAllDayEvent)
|
||||
calDavItem := CalDAVItem{HRef: uid + ".ics", ICal: ical}
|
||||
|
|
|
@ -131,7 +131,13 @@ over-the-shoulder "attacks".`,
|
|||
Run: runSettingsDecryption,
|
||||
}
|
||||
|
||||
settingsCmd.AddCommand(encryptCmd, decryptCmd)
|
||||
initCmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize an empty but valid settings file.",
|
||||
Run: runSettingsInit,
|
||||
}
|
||||
|
||||
settingsCmd.AddCommand(encryptCmd, decryptCmd, initCmd)
|
||||
return settingsCmd
|
||||
}
|
||||
|
||||
|
@ -225,6 +231,30 @@ func runSettingsDecryption(cmd *cobra.Command, args []string) {
|
|||
log.Println("Settings decrypted")
|
||||
}
|
||||
|
||||
func runSettingsInit(cmd *cobra.Command, args []string) {
|
||||
if _, err := os.Stat(settingsName); err == nil || os.IsExist(err) {
|
||||
log.Fatalln("You already have a settings file! Remove that first if you really want a new blank one!")
|
||||
}
|
||||
|
||||
s := Settings{}
|
||||
s.Anonymize.Title = &StringAnonSettings{ReplaceWith: "Replacement", Whitelist: []string{}}
|
||||
|
||||
// Rewrite the settings file.
|
||||
f, err := os.OpenFile(settingsName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not rewrite settings: %s\n", err)
|
||||
}
|
||||
defer f.Close()
|
||||
e := json.NewEncoder(f)
|
||||
e.SetIndent("", " ")
|
||||
err = e.Encode(&s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Println("Blank settings have been created.")
|
||||
}
|
||||
|
||||
// Apply the anonymization rule to the given string, returning the
|
||||
// anonymized version.
|
||||
// If the anonymization is nil or empty, the original string will
|
||||
|
|
Loading…
Reference in New Issue