This repository has been archived by the owner on Oct 26, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 113
/
PasswordManager.scala
162 lines (140 loc) · 4.56 KB
/
PasswordManager.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package sbtandroid
import sbt._
import Keys._
import AndroidPlugin._
object PasswordManager extends PWManager {
lazy val settings: Seq[Setting[_]] = (Seq (
clearPasswords <<= (streams) map { (s) =>
clear()
s.log.success("cleared passwords")
}
))
def fetch(service: String, account: String): Option[String] = impl.fetch(service, account)
def store(service: String, account: String, pw: String): Option[String] = impl.store(service, account, pw)
def delete(service: String, account: String): Boolean = impl.delete(service, account)
def clear() { impl.clear() }
lazy val impl: PWManager = {
System.getProperty("os.name") match {
case "Mac OS X" => OSXPasswordManager
case unknown => FilePasswordManager
}
}
}
trait PWManager {
def readPassword(service: String, account: String) =
SimpleReader.readLine("\nEnter password for "+service+"/"+account+": ").get
def get(service: String, account: String, cache: Boolean):Option[String] = {
fetch(service, account).orElse {
val pw = readPassword(service, account)
if (cache) store(service, account, pw) else Some(pw)
}
}
def fetch(service: String, account: String): Option[String]
def store(service: String, account: String, pw: String): Option[String]
def delete(service: String, account: String): Boolean
def clear()
}
object OSXPasswordManager extends PWManager {
val Label = "sbt-android-plugin"
def fetch(service: String, account: String): Option[String] = {
val buffer = new StringBuffer
Seq("security",
"find-generic-password",
"-a", account,
"-s", service, "-g").run(new ProcessIO(input => (),
output => (),
error => buffer.append(IO.readStream(error)),
inheritedInput => false)
).exitValue() match {
case 0 =>
(for (line <- buffer.toString.split("\r\n");
if (line.startsWith("password: ")))
yield line.substring(line.indexOf('"') + 1, line.lastIndexOf('"'))).headOption
case 44 =>
// password not stored yet
None
case _ => None
}
}
def store(service: String, account: String, pw: String): Option[String] = {
Seq("security",
"add-generic-password",
"-a", account,
"-s", service,
"-l", Label,
"-w", pw).run(false).exitValue() match {
case 0 => Some(pw)
case _ => None
}
}
def delete(service: String, account: String): Boolean = {
Seq("security",
"delete-generic-password",
"-a", account,
"-s", service).run(false).exitValue() == 0
}
def clear() {
if (Seq("security",
"delete-generic-password",
"-l", Label
).run(new ProcessIO(input => (), output => (), error => (), inheritedInput => false))
.exitValue() == 0) clear()
}
}
object EmptyPasswordManager extends PWManager {
def fetch(service: String, account: String) = None
def store(service: String, account: String, pw: String) = Some(pw)
def delete(service: String, account: String) = false
def clear() {}
}
object FilePasswordManager extends PWManager {
val pwDir = new File(new File(
System.getProperty("user.home"), ".sbt"), "sbt-android-plugin-passwords")
def file(service: String) = {
if (!pwDir.exists()) pwDir.mkdirs()
new File(pwDir, service)
}
def fetch(service: String, account: String) = {
val f = file(service)
if (f.exists()) (for (line <- IO.readLines(f);
if line.startsWith(account+"="))
yield line.substring(line.indexOf('=')+1)).headOption
else None
}
def store(service: String, account: String, pw: String) = {
val f = file(service)
val buffer = new StringBuffer
var replaced = false
def appendPw() = buffer.append(account).append("=").append(pw).append("\n")
if (f.exists()) {
for (line <- IO.readLines(f))
if (line.startsWith(account+"=")) {
appendPw()
replaced = true
} else buffer.append(line).append("\n")
if (!replaced) appendPw()
} else appendPw()
IO.write(f, buffer.toString.getBytes)
Some(pw)
}
def clear() {
if (pwDir.exists()) {
for (f <- pwDir.listFiles()) f.delete()
pwDir.delete()
}
}
def delete(service: String, account: String) = {
val f = file(service)
val buffer = new StringBuffer
var found = false
if (f.exists()) {
for (line <- IO.readLines(f)) {
if (!line.startsWith(account+"=")) {
buffer.append(line).append("\n")
} else found = true
}
IO.write(f, buffer.toString.getBytes)
found
} else false
}
}