Separate password management into its own module

This commit is contained in:
Correl Roush 2018-02-01 22:15:02 -05:00
parent 9db12cc731
commit f4f619b354
3 changed files with 168 additions and 86 deletions

View file

@ -5,6 +5,7 @@ import Gitlab
import Html import Html
import Html.Events as Events import Html.Events as Events
import Paginated import Paginated
import Pass
import Ports import Ports
import RemoteData import RemoteData
import Task import Task
@ -14,22 +15,16 @@ type alias ObjectsResponse =
RemoteData.WebData (List Gitlab.Object) RemoteData.WebData (List Gitlab.Object)
type alias State =
{ client : Gitlab.Client
, repo : Gitlab.Repo
, objects : ObjectsResponse
}
type Model type Model
= Loading = Loading
| Configuring Ports.Config | Configuring Ports.Config
| Configured State | Configured Pass.Model
type Msg type Msg
= Loaded (Maybe Ports.Config) = Loaded (Maybe Ports.Config)
| UpdateConfig Config.Msg | UpdateConfig Config.Msg
| UpdatePass Pass.Msg
| SaveConfig | SaveConfig
| Configure | Configure
| GotObjects ObjectsResponse | GotObjects ObjectsResponse
@ -57,15 +52,10 @@ subscriptions _ =
Ports.config Loaded Ports.config Loaded
loadConfig : Ports.Config -> Maybe State loadConfig : Ports.Config -> Maybe ( Pass.Model, Cmd Pass.Msg )
loadConfig cfg = loadConfig cfg =
Maybe.map2 Maybe.map2
(\client repo -> Pass.init
{ client = client
, repo = repo
, objects = RemoteData.NotAsked
}
)
(Config.toClient cfg) (Config.toClient cfg)
(Config.toRepo cfg) (Config.toRepo cfg)
@ -74,11 +64,14 @@ update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = update msg model =
case ( msg, model ) of case ( msg, model ) of
( Loaded loaded, Loading ) -> ( Loaded loaded, Loading ) ->
( Debug.log "loaded" loaded loaded
|> Maybe.andThen loadConfig |> Maybe.andThen loadConfig
|> Maybe.map Configured |> Maybe.map
|> Maybe.withDefault (Configuring Config.init) (\( state, cmd ) ->
|> Debug.log "configured" ( Configured state, Cmd.map UpdatePass cmd )
)
|> Maybe.withDefault
( Configuring Config.init
, Cmd.none , Cmd.none
) )
@ -91,22 +84,16 @@ update msg model =
( SaveConfig, Configuring cfg ) -> ( SaveConfig, Configuring cfg ) ->
let let
validated = validated =
Maybe.map2 Maybe.map2 Pass.init
(\client repo ->
{ client = client
, repo = repo
, objects = RemoteData.NotAsked
}
)
(Config.toClient cfg) (Config.toClient cfg)
(Config.toRepo cfg) (Config.toRepo cfg)
in in
case validated of case validated of
Just state -> Just ( state, cmd ) ->
( Configured state ( Configured state
, Cmd.batch , Cmd.batch
[ Ports.saveConfig cfg [ Ports.saveConfig cfg
, getObjects state.client state.repo , Cmd.map UpdatePass cmd
] ]
) )
@ -118,9 +105,13 @@ update msg model =
, Cmd.none , Cmd.none
) )
( GotObjects objects, Configured state ) -> ( UpdatePass m, Configured state ) ->
( Configured { state | objects = objects } let
, Cmd.none ( newstate, cmd ) =
Pass.update m state
in
( Configured newstate
, Cmd.map UpdatePass cmd
) )
_ -> _ ->
@ -141,53 +132,5 @@ view model =
] ]
Configured state -> Configured state ->
Html.div [] Html.map UpdatePass <|
[ Html.button [ Events.onClick Configure ] [ Html.text "Configure" ] Pass.view state
, Html.hr [] []
, viewFiles state.objects
]
viewFiles : ObjectsResponse -> Html.Html Msg
viewFiles data =
case data of
RemoteData.NotAsked ->
Html.div [] [ Html.text "Not loaded." ]
RemoteData.Failure _ ->
Html.div [] [ Html.text "Whoops." ]
RemoteData.Loading ->
Html.div [] [ Html.text "Loading objects..." ]
RemoteData.Success objects ->
let
files =
List.filter
(\o ->
o.objectType
== Gitlab.Blob
&& String.endsWith ".gpg" o.name
)
objects
in
Html.ul [] <|
List.map (\x -> Html.li [] [ viewFile x ]) files
viewFile : Gitlab.Object -> Html.Html Msg
viewFile file =
Html.text file.path
getConfig : Cmd Msg
getConfig =
Cmd.none
getObjects : Gitlab.Client -> Gitlab.Repo -> Cmd Msg
getObjects client repo =
Gitlab.getObjects repo client
|> Paginated.toTask
|> RemoteData.fromTask
|> Task.perform GotObjects

View file

@ -5,6 +5,7 @@ import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (decode, required) import Json.Decode.Pipeline exposing (decode, required)
import Maybe.Extra import Maybe.Extra
import Paginated import Paginated
import RemoteData exposing (WebData)
import Task exposing (Task) import Task exposing (Task)
@ -109,8 +110,12 @@ getObjects repo client =
client client
getFiles : Repo -> Client -> Task Http.Error (List Object) getFiles : Repo -> Client -> Task e (WebData (List String))
getFiles repo client = getFiles repo client =
getObjects repo client getObjects repo client
|> Paginated.toTask |> Paginated.toTask
|> Task.map (List.filter (\o -> o.objectType == Blob)) |> Task.map
(List.filter (.objectType >> (==) Blob))
|> Task.map
(List.map .path)
|> RemoteData.fromTask

134
src/Pass.elm Normal file
View file

@ -0,0 +1,134 @@
module Pass exposing (..)
import Dict exposing (Dict)
import Gitlab
import Html exposing (Html)
import Html.Attributes as Attr
import Html.Events as Events
import Maybe.Extra
import Paginated
import Regex
import RemoteData exposing (WebData)
import Task
type alias Pass =
List String
type alias Details =
{ password : String
, metadata : Dict String String
}
type alias Credentials =
{ password : String
, username : Maybe String
}
type alias Model =
{ client : Gitlab.Client
, repo : Gitlab.Repo
, entries : WebData (List Pass)
, filter : String
}
type Msg
= GotEntries (WebData (List Pass))
| UpdateFilter String
| Decrypt Pass
| Decrypted String
init : Gitlab.Client -> Gitlab.Repo -> ( Model, Cmd Msg )
init client repo =
( { client = client
, repo = repo
, entries = RemoteData.NotAsked
, filter = ""
}
, getEntries client repo
)
fromFilename : String -> Maybe Pass
fromFilename filename =
if String.endsWith ".gpg" filename then
String.dropRight 4 filename
|> String.split "/"
|> Just
else
Nothing
toFilename : Pass -> String
toFilename pass =
(String.join "/" pass) ++ ".gpg"
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotEntries entries ->
( { model | entries = entries }, Cmd.none )
UpdateFilter filter ->
( { model | filter = filter }, Cmd.none )
_ ->
( model, Cmd.none )
view : Model -> Html Msg
view model =
Html.div []
[ Html.input
[ Attr.value model.filter
, Events.onInput UpdateFilter
]
[]
, Html.hr [] []
, case model.entries of
RemoteData.NotAsked ->
Html.text "Loading"
RemoteData.Loading ->
Html.text "Loading..."
RemoteData.Failure _ ->
Html.text "Failed to load."
RemoteData.Success entries ->
Html.ul [] <|
List.map
(\x -> Html.li [] [ viewPass x ])
(filter model.filter entries)
]
filter : String -> List Pass -> List Pass
filter search entries =
let
regex =
Regex.caseInsensitive (Regex.regex search)
matches : String -> Pass -> Bool
matches search entry =
List.any (Regex.contains regex) entry
in
List.filter (matches search) entries
viewPass : Pass -> Html Msg
viewPass pass =
Html.text (String.join "/" pass)
getEntries : Gitlab.Client -> Gitlab.Repo -> Cmd Msg
getEntries client repo =
Gitlab.getFiles repo client
|> Task.map (RemoteData.map (List.map fromFilename >> Maybe.Extra.values))
|> Task.perform GotEntries