mirror of
https://github.com/dillonkearns/elm-pages-v3-beta.git
synced 2025-01-03 01:16:14 +03:00
Try all secrets in list for decoding signed cookies.
This commit is contained in:
parent
b7185adc39
commit
08e635cbeb
@ -57,41 +57,23 @@ withSession config decoder toRequest =
|
|||||||
Request.cookie config.name
|
Request.cookie config.name
|
||||||
|> Request.map
|
|> Request.map
|
||||||
(\maybeSessionCookie ->
|
(\maybeSessionCookie ->
|
||||||
--DataSource.succeed
|
|
||||||
-- (case maybeSessionCookie of
|
|
||||||
-- Just sessionCookie ->
|
|
||||||
-- Debug.todo ""
|
|
||||||
--
|
|
||||||
-- Nothing ->
|
|
||||||
-- Debug.todo ""
|
|
||||||
-- )
|
|
||||||
let
|
let
|
||||||
result : Result String decoded
|
decrypted : DataSource (Result String decoded)
|
||||||
result =
|
|
||||||
--Err ""
|
|
||||||
case maybeSessionCookie of
|
|
||||||
Nothing ->
|
|
||||||
Err "TODO"
|
|
||||||
|
|
||||||
Just sessionCookie ->
|
|
||||||
OptimizedDecoder.decodeString decoder sessionCookie
|
|
||||||
|> Result.mapError Json.Decode.errorToString
|
|
||||||
|
|
||||||
--decrypted : DataSource (Dict String Json.Decode.Value)
|
|
||||||
decrypted =
|
decrypted =
|
||||||
case maybeSessionCookie of
|
case maybeSessionCookie of
|
||||||
Just sessionCookie ->
|
Just sessionCookie ->
|
||||||
decrypt decoder sessionCookie
|
decrypt config.secrets decoder sessionCookie
|
||||||
|> DataSource.map Ok
|
|> DataSource.map Ok
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Err "TODO"
|
Err "TODO"
|
||||||
|> DataSource.succeed
|
|> DataSource.succeed
|
||||||
|
|
||||||
|
decryptedFull : DataSource (Dict String OptimizedDecoder.Value)
|
||||||
decryptedFull =
|
decryptedFull =
|
||||||
maybeSessionCookie
|
maybeSessionCookie
|
||||||
|> Maybe.map
|
|> Maybe.map
|
||||||
(\sessionCookie -> decrypt (OptimizedDecoder.dict OptimizedDecoder.value) sessionCookie)
|
(\sessionCookie -> decrypt config.secrets (OptimizedDecoder.dict OptimizedDecoder.value) sessionCookie)
|
||||||
|> Maybe.withDefault (DataSource.succeed Dict.empty)
|
|> Maybe.withDefault (DataSource.succeed Dict.empty)
|
||||||
in
|
in
|
||||||
decryptedFull
|
decryptedFull
|
||||||
@ -100,6 +82,7 @@ withSession config decoder toRequest =
|
|||||||
DataSource.andThen
|
DataSource.andThen
|
||||||
(\( sessionUpdate, response ) ->
|
(\( sessionUpdate, response ) ->
|
||||||
let
|
let
|
||||||
|
encodedCookie : Json.Encode.Value
|
||||||
encodedCookie =
|
encodedCookie =
|
||||||
Session.setValues sessionUpdate cookieDict
|
Session.setValues sessionUpdate cookieDict
|
||||||
in
|
in
|
||||||
@ -126,11 +109,6 @@ withSession config decoder toRequest =
|
|||||||
|
|
||||||
encrypt : Secrets.Value (List String) -> Json.Encode.Value -> DataSource.DataSource String
|
encrypt : Secrets.Value (List String) -> Json.Encode.Value -> DataSource.DataSource String
|
||||||
encrypt secrets input =
|
encrypt secrets input =
|
||||||
let
|
|
||||||
decoder : OptimizedDecoder.Decoder String
|
|
||||||
decoder =
|
|
||||||
OptimizedDecoder.string
|
|
||||||
in
|
|
||||||
DataSource.Http.request
|
DataSource.Http.request
|
||||||
(secrets
|
(secrets
|
||||||
|> Secrets.map
|
|> Secrets.map
|
||||||
@ -140,31 +118,44 @@ encrypt secrets input =
|
|||||||
, headers = []
|
, headers = []
|
||||||
|
|
||||||
-- TODO pass through secrets here
|
-- TODO pass through secrets here
|
||||||
, body = DataSource.Http.jsonBody input
|
, body =
|
||||||
|
DataSource.Http.jsonBody
|
||||||
|
(Json.Encode.object
|
||||||
|
[ ( "values", input )
|
||||||
|
, ( "secret"
|
||||||
|
, Json.Encode.string
|
||||||
|
(secretList
|
||||||
|
|> List.head
|
||||||
|
-- TODO use different default - require non-empty list?
|
||||||
|
|> Maybe.withDefault ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
decoder
|
OptimizedDecoder.string
|
||||||
|
|
||||||
|
|
||||||
|
decrypt : Secrets.Value (List String) -> OptimizedDecoder.Decoder a -> String -> DataSource a
|
||||||
--decrypt : String -> DataSource.DataSource (Dict String Json.Decode.Value)
|
decrypt secrets decoder input =
|
||||||
|
|
||||||
|
|
||||||
decrypt : OptimizedDecoder.Decoder a -> String -> DataSource a
|
|
||||||
decrypt decoder input =
|
|
||||||
--let
|
|
||||||
-- decoder : OptimizedDecoder.Decoder (Dict String Json.Decode.Value)
|
|
||||||
-- decoder =
|
|
||||||
-- OptimizedDecoder.dict OptimizedDecoder.value
|
|
||||||
--in
|
|
||||||
DataSource.Http.request
|
DataSource.Http.request
|
||||||
(Secrets.succeed
|
(secrets
|
||||||
{ url = "port://decrypt"
|
|> Secrets.map
|
||||||
, method = "GET"
|
(\secretList ->
|
||||||
, headers = []
|
{ url = "port://decrypt"
|
||||||
, body = DataSource.Http.jsonBody (Json.Encode.string input)
|
, method = "GET"
|
||||||
}
|
, headers = []
|
||||||
|
, body =
|
||||||
|
DataSource.Http.jsonBody
|
||||||
|
(Json.Encode.object
|
||||||
|
[ ( "input", Json.Encode.string input )
|
||||||
|
, ( "secrets", Json.Encode.list Json.Encode.string secretList )
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
decoder
|
decoder
|
||||||
|
|
||||||
@ -201,35 +192,11 @@ data routeParams =
|
|||||||
-- ("hello " ++ requestData.username ++ "!")
|
-- ("hello " ++ requestData.username ++ "!")
|
||||||
-- |> DataSource.succeed
|
-- |> DataSource.succeed
|
||||||
-- ),
|
-- ),
|
||||||
--, withSession
|
|
||||||
-- { name = "__session"
|
|
||||||
-- , secrets =
|
|
||||||
-- Secrets.succeed
|
|
||||||
-- (\sessionSecret -> [ sessionSecret ])
|
|
||||||
-- |> Secrets.with "SESSION_SECRET"
|
|
||||||
-- , sameSite = "lax" -- TODO custom type
|
|
||||||
-- , codec =
|
|
||||||
-- -- TODO use custom codec API, allowing you to retrieve fields, decode them, and set fields with flash
|
|
||||||
-- Codec.object identity
|
|
||||||
-- |> Codec.field "userId" identity Codec.string
|
|
||||||
-- |> Codec.buildObject
|
|
||||||
-- }
|
|
||||||
-- (\userIdResult ->
|
|
||||||
-- case userIdResult of
|
|
||||||
-- Err error ->
|
|
||||||
-- Debug.todo ""
|
|
||||||
--
|
|
||||||
-- Ok userId ->
|
|
||||||
-- Request.succeed
|
|
||||||
-- (DataSource.succeed
|
|
||||||
-- ( userId, Server.Response.temporaryRedirect "/login" )
|
|
||||||
-- )
|
|
||||||
-- )
|
|
||||||
withSession
|
withSession
|
||||||
{ name = "mysession"
|
{ name = "mysession"
|
||||||
, secrets =
|
, secrets =
|
||||||
Secrets.succeed
|
Secrets.succeed
|
||||||
(\sessionSecret -> [ sessionSecret ])
|
(\sessionSecret -> [ "secret4", "secret3", "secret2", sessionSecret ])
|
||||||
|> Secrets.with "SESSION_SECRET"
|
|> Secrets.with "SESSION_SECRET"
|
||||||
, sameSite = "lax" -- TODO custom type
|
, sameSite = "lax" -- TODO custom type
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ const path = require("path");
|
|||||||
const undici = require("undici");
|
const undici = require("undici");
|
||||||
const objectHash = require("object-hash");
|
const objectHash = require("object-hash");
|
||||||
const kleur = require("kleur");
|
const kleur = require("kleur");
|
||||||
|
const cookie = require("cookie-signature");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To cache HTTP requests on disk with quick lookup and insertion, we store the hashed request.
|
* To cache HTTP requests on disk with quick lookup and insertion, we store the hashed request.
|
||||||
@ -56,26 +57,13 @@ function lookupOrPerform(mode, rawRequest, hasFsAccess) {
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (request.url === "port://encrypt") {
|
if (request.url === "port://encrypt") {
|
||||||
const cookie = require("cookie-signature");
|
|
||||||
console.log(
|
|
||||||
"@@@signing",
|
|
||||||
rawRequest.body.args[0],
|
|
||||||
typeof rawRequest.body.args[0]
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
"signed",
|
|
||||||
cookie.sign(
|
|
||||||
JSON.stringify(rawRequest.body.args[0], null, 0),
|
|
||||||
"abcdefg"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
await fs.promises.writeFile(
|
await fs.promises.writeFile(
|
||||||
responsePath,
|
responsePath,
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
cookie.sign(
|
cookie.sign(
|
||||||
JSON.stringify(rawRequest.body.args[0], null, 0),
|
JSON.stringify(rawRequest.body.args[0].values, null, 0),
|
||||||
"abcdefg"
|
rawRequest.body.args[0].secret
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -91,18 +79,14 @@ function lookupOrPerform(mode, rawRequest, hasFsAccess) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (request.url === "port://decrypt") {
|
} else if (request.url === "port://decrypt") {
|
||||||
const cookie = require("cookie-signature");
|
|
||||||
console.log("@@@[0]", rawRequest.body.args[0]);
|
|
||||||
try {
|
try {
|
||||||
console.log(
|
|
||||||
"unsigned",
|
|
||||||
cookie.unsign(rawRequest.body.args[0], "abcdefg")
|
|
||||||
);
|
|
||||||
// TODO if unsign returns `false`, need to have an `Err` in Elm because decryption failed
|
// TODO if unsign returns `false`, need to have an `Err` in Elm because decryption failed
|
||||||
await fs.promises.writeFile(
|
const signed = tryDecodeCookie(
|
||||||
responsePath,
|
rawRequest.body.args[0].input,
|
||||||
cookie.unsign(rawRequest.body.args[0], "abcdefg")
|
rawRequest.body.args[0].secrets
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await fs.promises.writeFile(responsePath, signed);
|
||||||
resolve(responsePath);
|
resolve(responsePath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject({
|
reject({
|
||||||
@ -181,6 +165,19 @@ function lookupOrPerform(mode, rawRequest, hasFsAccess) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tryDecodeCookie(input, secrets) {
|
||||||
|
if (secrets.length > 0) {
|
||||||
|
const signed = cookie.unsign(input, secrets[0]);
|
||||||
|
if (signed) {
|
||||||
|
return signed;
|
||||||
|
} else {
|
||||||
|
return tryDecodeCookie(input, secrets.slice(1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {{url: string; headers: {[x: string]: string}; method: string; body: Body } } elmRequest
|
* @param {{url: string; headers: {[x: string]: string}; method: string; body: Body } } elmRequest
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user