mbkauthe 4.8.3 → 4.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -6
- package/docs/api.md +45 -27
- package/docs/auth-flows.mmd +9 -9
- package/docs/auth-processes.mmd +71 -0
- package/docs/db.md +36 -276
- package/docs/db.sql +6 -9
- package/docs/env.md +2 -8
- package/docs/error-messages.md +3 -3
- package/docs/images/auth-flows.svg +1 -1
- package/docs/images/auth-process.svg +1 -0
- package/index.d.ts +1 -2
- package/index.js +1 -1
- package/lib/config/cookies.js +6 -6
- package/lib/config/index.js +4 -10
- package/lib/createTable.js +5 -5
- package/lib/middleware/auth.js +27 -17
- package/lib/middleware/index.js +2 -2
- package/lib/pool.js +2 -2
- package/lib/routes/auth.js +26 -38
- package/lib/routes/dbLogs.js +3 -3
- package/lib/routes/misc.js +22 -22
- package/lib/utils/timingSafeToken.js +35 -0
- package/package.json +1 -1
- package/public/main.js +3 -3
- package/views/Error/dError.handlebars +1 -1
- package/views/pages/accountSwitch.handlebars +4 -4
- package/views/pages/loginmbkauthe.handlebars +1 -1
- package/views/profilemenu.handlebars +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="max-width: 928px; background-color: white;" viewBox="-50 -10 928 2389" role="graphics-document document" aria-roledescription="sequence"><rect x="34" y="1068" fill="rgb(245, 245, 245)" width="764" height="1215" class="rect"/><rect x="44" y="1695" fill="rgb(220, 230, 250)" width="744" height="578" class="rect"/><rect x="44" y="1181" fill="rgb(240, 240, 240)" width="744" height="504" class="rect"/><rect x="40" y="75" fill="rgb(235, 245, 255)" width="748" height="983" class="rect"/><g><rect x="678" y="2303" fill="#eaeaea" stroke="#666" width="150" height="65" name="DB" rx="3" ry="3" class="actor actor-bottom"/><text x="753" y="2335.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="753" dy="0">Database</tspan></text></g><g><rect x="339" y="2303" fill="#eaeaea" stroke="#666" width="150" height="65" name="S" rx="3" ry="3" class="actor actor-bottom"/><text x="414" y="2335.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="414" dy="0">Server</tspan></text></g><g><rect x="0" y="2303" fill="#eaeaea" stroke="#666" width="150" height="65" name="C" rx="3" ry="3" class="actor actor-bottom"/><text x="75" y="2335.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="75" dy="0">Client</tspan></text></g><g><line id="actor2" x1="753" y1="65" x2="753" y2="2303" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="DB" data-et="life-line" data-id="DB"/><g id="root-2" data-et="participant" data-type="participant" data-id="DB"><rect x="678" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="DB" rx="3" ry="3" class="actor actor-top"/><text x="753" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="753" dy="0">Database</tspan></text></g></g><g><line id="actor1" x1="414" y1="65" x2="414" y2="2303" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="S" data-et="life-line" data-id="S"/><g id="root-1" data-et="participant" data-type="participant" data-id="S"><rect x="339" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="S" rx="3" ry="3" class="actor actor-top"/><text x="414" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="414" dy="0">Server</tspan></text></g></g><g><line id="actor0" x1="75" y1="65" x2="75" y2="2303" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="C" data-et="life-line" data-id="C"/><g id="root-0" data-et="participant" data-type="participant" data-id="C"><rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="C" rx="3" ry="3" class="actor actor-top"/><text x="75" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="75" dy="0">Client</tspan></text></g></g><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#333333;stroke:#333333;}#my-svg .marker.cross{stroke:#333333;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .actor{stroke:#9370DB;fill:#ECECFF;stroke-width:1;}#my-svg rect.actor.outer-path[data-look="neo"]{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg rect.note[data-look="neo"]{stroke:#aaaa33;fill:#fff5ad;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg text.actor>tspan{fill:black;stroke:none;}#my-svg .actor-line{stroke:#9370DB;}#my-svg .innerArc{stroke-width:1.5;stroke-dasharray:none;}#my-svg .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#my-svg .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#my-svg [id$="-arrowhead"] path{fill:#333;stroke:#333;}#my-svg .sequenceNumber{fill:white;}#my-svg [id$="-sequencenumber"]{fill:#333;}#my-svg [id$="-crosshead"] path{fill:#333;stroke:#333;}#my-svg .messageText{fill:#333;stroke:none;}#my-svg .labelBox{stroke:#9370DB;fill:#ECECFF;filter:none;}#my-svg .labelText,#my-svg .labelText>tspan{fill:black;stroke:none;}#my-svg .loopText,#my-svg .loopText>tspan{fill:black;stroke:none;}#my-svg .sectionTitle,#my-svg .sectionTitle>tspan{fill:black;stroke:none;}#my-svg .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:#9370DB;fill:#9370DB;}#my-svg .note{stroke:#aaaa33;fill:#fff5ad;}#my-svg .noteText,#my-svg .noteText>tspan{fill:black;stroke:none;font-weight:normal;}#my-svg .activation0{fill:#f4f4f4;stroke:#666;}#my-svg .activation1{fill:#f4f4f4;stroke:#666;}#my-svg .activation2{fill:#f4f4f4;stroke:#666;}#my-svg .actorPopupMenu{position:absolute;}#my-svg .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#my-svg .actor-man circle,#my-svg line{fill:#ECECFF;stroke-width:2px;}#my-svg g rect.rect{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));stroke:#9370DB;}#my-svg .node .neo-node{stroke:#9370DB;}#my-svg [data-look="neo"].node rect,#my-svg [data-look="neo"].cluster rect,#my-svg [data-look="neo"].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node path{stroke:#9370DB;stroke-width:1px;}#my-svg [data-look="neo"].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node .neo-line path{stroke:#9370DB;filter:none;}#my-svg [data-look="neo"].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].node circle .state-start{fill:#000000;}#my-svg [data-look="neo"].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg [data-look="neo"].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g/><defs><symbol id="my-svg-computer" width="24" height="24"><path transform="scale(.5)" d="M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z"/></symbol></defs><defs><symbol id="my-svg-database" fill-rule="evenodd" clip-rule="evenodd"><path transform="scale(.5)" d="M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z"/></symbol></defs><defs><symbol id="my-svg-clock" width="24" height="24"><path transform="scale(.5)" d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z"/></symbol></defs><defs><marker id="my-svg-arrowhead" refX="7.9" refY="5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"><path d="M -1 0 L 10 5 L 0 10 z"/></marker></defs><defs><marker id="my-svg-crosshead" markerWidth="15" markerHeight="8" orient="auto" refX="4" refY="4.5"><path fill="none" stroke="#000000" stroke-width="1pt" d="M 1,2 L 6,7 M 6,2 L 1,7" style="stroke-dasharray: 0, 0;"/></marker></defs><defs><marker id="my-svg-filled-head" refX="15.5" refY="7" markerWidth="20" markerHeight="28" orient="auto"><path d="M 18,7 L9,13 L14,7 L9,1 Z"/></marker></defs><defs><marker id="my-svg-sequencenumber" refX="15" refY="15" markerWidth="60" markerHeight="40" orient="auto"><circle cx="15" cy="15" r="6"/></marker></defs><defs><marker id="my-svg-solidTopArrowHead" refX="7.9" refY="7.25" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"><path d="M 0 0 L 10 8 L 0 8 z"/></marker></defs><defs><marker id="my-svg-solidBottomArrowHead" refX="7.9" refY="0.75" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"><path d="M 0 0 L 10 0 L 0 8 z"/></marker></defs><defs><marker id="my-svg-stickTopArrowHead" refX="7.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"><path d="M 0 0 L 7 7" stroke="black" stroke-width="1.5" fill="none"/></marker></defs><defs><marker id="my-svg-stickBottomArrowHead" refX="7.5" refY="0" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"><path d="M 0 7 L 7 0" stroke="black" stroke-width="1.5" fill="none"/></marker></defs><g data-et="note" data-id="i1"><rect x="50" y="95" fill="#EDF2AE" stroke="#666" width="728" height="39" class="note"/><text x="414" y="100" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"><tspan x="414">Authentication Flow</tspan></text></g><g data-et="control-structure" data-id="i13"><line x1="64" y1="424" x2="764" y2="424" class="loopLine"/><line x1="764" y1="424" x2="764" y2="749" class="loopLine"/><line x1="64" y1="749" x2="764" y2="749" class="loopLine"/><line x1="64" y1="424" x2="64" y2="749" class="loopLine"/><polygon points="64,424 114,424 114,437 105.6,444 64,444" class="labelBox"/><text x="89" y="437" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="labelText" style="font-size: 16px; font-weight: 400;">alt</text><text x="439" y="442" text-anchor="middle" class="loopText" style="font-size: 16px; font-weight: 400;"><tspan x="439">[2FA Enabled & Device Not Trusted]</tspan></text></g><g data-et="note" data-id="i14"><rect x="389" y="759" fill="#EDF2AE" stroke="#666" width="389" height="39" class="note"/><text x="584" y="764" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"><tspan x="584">completeLoginProcess</tspan></text></g><g data-et="note" data-id="i22"><rect x="50" y="1088" fill="#EDF2AE" stroke="#666" width="728" height="39" class="note"/><text x="414" y="1093" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"><tspan x="414">Request Authentication Middleware Flow</tspan></text></g><g data-et="note" data-id="i25"><rect x="389" y="1201" fill="#EDF2AE" stroke="#666" width="389" height="39" class="note"/><text x="584" y="1206" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"><tspan x="584">Token Path (API)</tspan></text></g><g data-et="control-structure" data-id="i34"><line x1="64" y1="1413" x2="764" y2="1413" class="loopLine"/><line x1="764" y1="1413" x2="764" y2="1665" class="loopLine"/><line x1="64" y1="1665" x2="764" y2="1665" class="loopLine"/><line x1="64" y1="1413" x2="64" y2="1665" class="loopLine"/><line x1="64" y1="1581" x2="764" y2="1581" class="loopLine" style="stroke-dasharray: 3, 3;"/><polygon points="64,1413 114,1413 114,1426 105.6,1433 64,1433" class="labelBox"/><text x="89" y="1426" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="labelText" style="font-size: 16px; font-weight: 400;">alt</text><text x="439" y="1431" text-anchor="middle" class="loopText" style="font-size: 16px; font-weight: 400;"><tspan x="439">[Valid & Not Expired]</tspan></text><text x="414" y="1599" text-anchor="middle" class="sectionTitle" style="font-size: 16px; font-weight: 400;">[Invalid/Expired]</text></g><g data-et="control-structure" data-id="i35"><line x1="54" y1="1250" x2="774" y2="1250" class="loopLine"/><line x1="774" y1="1250" x2="774" y2="1675" class="loopLine"/><line x1="54" y1="1675" x2="774" y2="1675" class="loopLine"/><line x1="54" y1="1250" x2="54" y2="1675" class="loopLine"/><polygon points="54,1250 104,1250 104,1263 95.6,1270 54,1270" class="labelBox"/><text x="79" y="1263" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="labelText" style="font-size: 16px; font-weight: 400;">alt</text><text x="439" y="1268" text-anchor="middle" class="loopText" style="font-size: 16px; font-weight: 400;"><tspan x="439">[Header: Bearer mbk_token]</tspan></text></g><g data-et="note" data-id="i38"><rect x="389" y="1715" fill="#EDF2AE" stroke="#666" width="389" height="39" class="note"/><text x="584" y="1720" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="noteText" dy="1em" style="font-size: 16px; font-weight: 400;"><tspan x="584">Session Path (Web)</tspan></text></g><g data-et="control-structure" data-id="i48"><line x1="64" y1="1897" x2="543.5" y2="1897" class="loopLine"/><line x1="543.5" y1="1897" x2="543.5" y2="2253" class="loopLine"/><line x1="64" y1="2253" x2="543.5" y2="2253" class="loopLine"/><line x1="64" y1="1897" x2="64" y2="2253" class="loopLine"/><line x1="64" y1="2095" x2="543.5" y2="2095" class="loopLine" style="stroke-dasharray: 3, 3;"/><polygon points="64,1897 114,1897 114,1910 105.6,1917 64,1917" class="labelBox"/><text x="89" y="1910" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="labelText" style="font-size: 16px; font-weight: 400;">alt</text><text x="328.75" y="1915" text-anchor="middle" class="loopText" style="font-size: 16px; font-weight: 400;"><tspan x="328.75">[Session Valid & User Active]</tspan></text><text x="303.75" y="2113" text-anchor="middle" class="sectionTitle" style="font-size: 16px; font-weight: 400;">[Session Expired/User Inactive]</text></g><g data-et="control-structure" data-id="i49"><line x1="54" y1="1764" x2="764" y2="1764" class="loopLine"/><line x1="764" y1="1764" x2="764" y2="2263" class="loopLine"/><line x1="54" y1="2263" x2="764" y2="2263" class="loopLine"/><line x1="54" y1="1764" x2="54" y2="2263" class="loopLine"/><polygon points="54,1764 104,1764 104,1777 95.6,1784 54,1784" class="labelBox"/><text x="79" y="1777" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="labelText" style="font-size: 16px; font-weight: 400;">alt</text><text x="434" y="1782" text-anchor="middle" class="loopText" style="font-size: 16px; font-weight: 400;"><tspan x="434">[Cookie: sessionId exists]</tspan></text></g><text x="243" y="149" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">POST /login (username, password)</text><line x1="76" y1="178" x2="410" y2="178" class="messageLine0" data-et="message" data-id="i2" data-from="C" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="415" y="193" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Validate payload format</text><path d="M 415,222 C 475,212 475,252 415,242" class="messageLine0" data-et="message" data-id="i3" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="267" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Query User & 2FA status</text><line x1="415" y1="296" x2="749" y2="296" class="messageLine0" data-et="message" data-id="i4" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="585" y="311" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">User Data (Password Hash, 2FA Enabled)</text><line x1="752" y1="340" x2="418" y2="340" class="messageLine1" data-et="message" data-id="i5" data-from="DB" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/><text x="415" y="355" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Compare Hash (PasswordEnc)</text><path d="M 415,384 C 475,374 475,414 415,404" class="messageLine0" data-et="message" data-id="i6" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="246" y="474" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">200 (twoFactorRequired: true)</text><line x1="413" y1="503" x2="79" y2="503" class="messageLine1" data-et="message" data-id="i8" data-from="S" data-to="C" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/><text x="243" y="518" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">POST /verify-2fa (TOTP Token)</text><line x1="76" y1="547" x2="410" y2="547" class="messageLine0" data-et="message" data-id="i9" data-from="C" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="562" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Fetch TOTP Secret</text><line x1="415" y1="591" x2="749" y2="591" class="messageLine0" data-et="message" data-id="i10" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="585" y="606" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Secret Key</text><line x1="752" y1="635" x2="418" y2="635" class="messageLine1" data-et="message" data-id="i11" data-from="DB" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/><text x="415" y="650" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Verify TOTP</text><path d="M 415,679 C 475,669 475,709 415,699" class="messageLine0" data-et="message" data-id="i12" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="813" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Delete old sessions & Prune max sessions</text><line x1="415" y1="842" x2="749" y2="842" class="messageLine0" data-et="message" data-id="i15" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="415" y="857" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Regenerate Session ID</text><path d="M 415,886 C 475,876 475,916 415,906" class="messageLine0" data-et="message" data-id="i16" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="931" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Insert new Session row</text><line x1="415" y1="960" x2="749" y2="960" class="messageLine0" data-et="message" data-id="i17" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="975" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Update Users.last_login</text><line x1="415" y1="1004" x2="749" y2="1004" class="messageLine0" data-et="message" data-id="i18" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="246" y="1019" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">200 Success (Set Encrypted Cookies)</text><line x1="413" y1="1048" x2="79" y2="1048" class="messageLine1" data-et="message" data-id="i19" data-from="S" data-to="C" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/><text x="243" y="1142" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Request + Auth (Cookie or Bearer Token)</text><line x1="76" y1="1171" x2="410" y2="1171" class="messageLine0" data-et="message" data-id="i23" data-from="C" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="415" y="1300" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Hash Token</text><path d="M 415,1329 C 475,1319 475,1359 415,1349" class="messageLine0" data-et="message" data-id="i27" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="1374" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Query ApiTokens JOIN Users</text><line x1="415" y1="1403" x2="749" y2="1403" class="messageLine0" data-et="message" data-id="i28" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="582" y="1463" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Update last_used</text><line x1="415" y1="1492" x2="749" y2="1492" class="messageLine0" data-et="message" data-id="i30" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="415" y="1507" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Authorize Scope</text><path d="M 415,1536 C 475,1526 475,1566 415,1556" class="messageLine0" data-et="message" data-id="i31" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="246" y="1626" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">401 Unauthorized</text><line x1="413" y1="1655" x2="79" y2="1655" class="messageLine1" data-et="message" data-id="i33" data-from="S" data-to="C" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/><text x="582" y="1814" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Query Sessions JOIN Users</text><line x1="415" y1="1843" x2="749" y2="1843" class="messageLine0" data-et="message" data-id="i40" data-from="S" data-to="DB" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="585" y="1858" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Session Data + User Status</text><line x1="752" y1="1887" x2="418" y2="1887" class="messageLine1" data-et="message" data-id="i41" data-from="DB" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/><text x="415" y="1947" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Sync Cookies & Update session.user</text><path d="M 415,1976 C 475,1966 475,2006 415,1996" class="messageLine0" data-et="message" data-id="i43" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="415" y="2021" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Proceed to Route</text><path d="M 415,2050 C 475,2040 475,2080 415,2070" class="messageLine0" data-et="message" data-id="i44" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="415" y="2140" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Destroy Session & Clear Cookies</text><path d="M 415,2169 C 475,2159 475,2199 415,2189" class="messageLine0" data-et="message" data-id="i46" data-from="S" data-to="S" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="fill: none;"/><text x="246" y="2214" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">403 Forbidden</text><line x1="413" y1="2243" x2="79" y2="2243" class="messageLine1" data-et="message" data-id="i47" data-from="S" data-to="C" stroke-width="2" stroke="none" marker-end="url(#my-svg-arrowhead)" style="stroke-dasharray: 3, 3; fill: none;"/></svg>
|
package/index.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ declare module 'mbkauthe' {
|
|
|
62
62
|
GOOGLE_CLIENT_ID?: string;
|
|
63
63
|
GOOGLE_CLIENT_SECRET?: string;
|
|
64
64
|
loginRedirectURL?: string;
|
|
65
|
-
|
|
65
|
+
MAX_SESSIONS_PER_USER?: number;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export interface OAuthConfig {
|
|
@@ -100,7 +100,6 @@ declare module 'mbkauthe' {
|
|
|
100
100
|
export interface DBUser {
|
|
101
101
|
id: number;
|
|
102
102
|
UserName: string;
|
|
103
|
-
Password?: string;
|
|
104
103
|
PasswordEnc?: string;
|
|
105
104
|
Role: UserRole;
|
|
106
105
|
Active: boolean;
|
package/index.js
CHANGED
|
@@ -58,7 +58,7 @@ const renderDevError = (res, req, code, error, message, page, details) => render
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
if (isDevMode) {
|
|
61
|
-
console.log(
|
|
61
|
+
console.log(`[mbkauthe] Dev mode is enabled. Starting server in dev mode.`);
|
|
62
62
|
|
|
63
63
|
app.get(["/dashboard", "/home", "/"], (req, res) => res.redirect("/mbkauthe/"));
|
|
64
64
|
|
package/lib/config/cookies.js
CHANGED
|
@@ -33,7 +33,7 @@ const encryptCookiePayload = (data) => {
|
|
|
33
33
|
data: encrypted
|
|
34
34
|
};
|
|
35
35
|
} catch (error) {
|
|
36
|
-
console.error(
|
|
36
|
+
console.error(`[mbkauthe] Cookie encryption error:`, error);
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
};
|
|
@@ -59,7 +59,7 @@ const decryptCookiePayload = (payload) => {
|
|
|
59
59
|
|
|
60
60
|
return JSON.parse(decrypted);
|
|
61
61
|
} catch (error) {
|
|
62
|
-
console.error(
|
|
62
|
+
console.error(`[mbkauthe] Cookie decryption error:`, error);
|
|
63
63
|
return null;
|
|
64
64
|
}
|
|
65
65
|
};
|
|
@@ -93,7 +93,7 @@ export const decryptSessionId = (encryptedSessionId) => {
|
|
|
93
93
|
const decrypted = decryptCookiePayload(parsed);
|
|
94
94
|
return decrypted?.sessionId || null;
|
|
95
95
|
} catch (error) {
|
|
96
|
-
console.error(
|
|
96
|
+
console.error(`[mbkauthe] SessionId decryption error:`, error);
|
|
97
97
|
return null;
|
|
98
98
|
}
|
|
99
99
|
};
|
|
@@ -171,7 +171,7 @@ const parseAccountList = (raw, req) => {
|
|
|
171
171
|
// Verify fingerprint matches current request
|
|
172
172
|
const currentFingerprint = generateFingerprint(req);
|
|
173
173
|
if (decrypted.fingerprint !== currentFingerprint) {
|
|
174
|
-
console.warn(
|
|
174
|
+
console.warn(`[mbkauthe] Cookie fingerprint mismatch - possible cookie theft attempt`);
|
|
175
175
|
return [];
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -190,7 +190,7 @@ const parseAccountList = (raw, req) => {
|
|
|
190
190
|
.filter(item => item.sessionId && item.username)
|
|
191
191
|
.slice(0, MAX_REMEMBERED_ACCOUNTS);
|
|
192
192
|
} catch (error) {
|
|
193
|
-
console.error(
|
|
193
|
+
console.error(`[mbkauthe] Error parsing account list:`, error);
|
|
194
194
|
return [];
|
|
195
195
|
}
|
|
196
196
|
};
|
|
@@ -215,7 +215,7 @@ const writeAccountList = (res, list, req) => {
|
|
|
215
215
|
// Encrypt the payload
|
|
216
216
|
const encrypted = encryptCookiePayload(payload);
|
|
217
217
|
if (!encrypted) {
|
|
218
|
-
console.error(
|
|
218
|
+
console.error(`[mbkauthe] Failed to encrypt account list cookie`);
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
221
|
|
package/lib/config/index.js
CHANGED
|
@@ -34,12 +34,12 @@ function validateConfiguration() {
|
|
|
34
34
|
if (process.env.mbkauthShared) {
|
|
35
35
|
mbkauthShared = JSON.parse(process.env.mbkauthShared);
|
|
36
36
|
if (mbkauthShared && typeof mbkauthShared !== 'object') {
|
|
37
|
-
console.warn(
|
|
37
|
+
console.warn(`[mbkauthe] mbkauthShared is not a valid object, ignoring it`);
|
|
38
38
|
mbkauthShared = null;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
} catch (error) {
|
|
42
|
-
console.warn(
|
|
42
|
+
console.warn(`[mbkauthe] Invalid JSON in process.env.mbkauthShared, ignoring it`);
|
|
43
43
|
mbkauthShared = null;
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -62,7 +62,7 @@ function validateConfiguration() {
|
|
|
62
62
|
|
|
63
63
|
// Ensure specific keys are checked in mbkautheVar first, then mbkauthShared, then apply config defaults
|
|
64
64
|
const keysToCheck = [
|
|
65
|
-
"APP_NAME", "DEVICE_TRUST_DURATION_DAYS", "
|
|
65
|
+
"APP_NAME", "DEVICE_TRUST_DURATION_DAYS", "Main_SECRET_TOKEN", "SESSION_SECRET_KEY",
|
|
66
66
|
"IS_DEPLOYED", "LOGIN_DB", "MBKAUTH_TWO_FA_ENABLE", "COOKIE_EXPIRE_TIME", "DOMAIN", "loginRedirectURL",
|
|
67
67
|
"GITHUB_LOGIN_ENABLED", "GITHUB_APP_SLUG", "GITHUB_APP_CLIENT_ID", "GITHUB_APP_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "GOOGLE_LOGIN_ENABLED", "GOOGLE_CLIENT_ID",
|
|
68
68
|
"GOOGLE_CLIENT_SECRET", "MAX_SESSIONS_PER_USER"
|
|
@@ -70,7 +70,6 @@ function validateConfiguration() {
|
|
|
70
70
|
|
|
71
71
|
const defaults = {
|
|
72
72
|
DEVICE_TRUST_DURATION_DAYS: 7,
|
|
73
|
-
EncPass: 'false',
|
|
74
73
|
IS_DEPLOYED: 'false',
|
|
75
74
|
MBKAUTH_TWO_FA_ENABLE: 'false',
|
|
76
75
|
COOKIE_EXPIRE_TIME: 2,
|
|
@@ -95,7 +94,7 @@ function validateConfiguration() {
|
|
|
95
94
|
});
|
|
96
95
|
|
|
97
96
|
// Normalize boolean-like values to consistent lowercase 'true'/'false' strings
|
|
98
|
-
['GITHUB_LOGIN_ENABLED', 'GOOGLE_LOGIN_ENABLED', 'MBKAUTH_TWO_FA_ENABLE', 'IS_DEPLOYED'
|
|
97
|
+
['GITHUB_LOGIN_ENABLED', 'GOOGLE_LOGIN_ENABLED', 'MBKAUTH_TWO_FA_ENABLE', 'IS_DEPLOYED'].forEach(k => {
|
|
99
98
|
const val = mbkautheVar[k];
|
|
100
99
|
if (typeof val === 'boolean') {
|
|
101
100
|
mbkautheVar[k] = val ? 'true' : 'false';
|
|
@@ -138,11 +137,6 @@ function validateConfiguration() {
|
|
|
138
137
|
errors.push("mbkautheVar.GOOGLE_LOGIN_ENABLED must be either 'true' or 'false' or 'f'");
|
|
139
138
|
}
|
|
140
139
|
|
|
141
|
-
// Validate EncPass value if provided
|
|
142
|
-
if (mbkautheVar.EncPass && !['true', 'false', 'f'].includes(mbkautheVar.EncPass.toLowerCase())) {
|
|
143
|
-
errors.push("mbkautheVar.EncPass must be either 'true' or 'false' or 'f'");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
140
|
// Validate GitHub login configuration
|
|
147
141
|
if (mbkautheVar.GITHUB_LOGIN_ENABLED === "true") {
|
|
148
142
|
const hasGithubClientId = !!(mbkautheVar.GITHUB_APP_CLIENT_ID || mbkautheVar.GITHUB_CLIENT_ID);
|
package/lib/createTable.js
CHANGED
|
@@ -12,18 +12,18 @@ async function main() {
|
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
14
|
const res = await dblogin.query(schemaSql);
|
|
15
|
-
console.log(
|
|
15
|
+
console.log(`[mbkauthe] Schema applied successfully.`);
|
|
16
16
|
if (res?.rows?.length) {
|
|
17
|
-
console.log(res.rows);
|
|
17
|
+
console.log(`[mbkauthe] Rows returned by schema query:`, res.rows);
|
|
18
18
|
} else {
|
|
19
|
-
console.log(
|
|
19
|
+
console.log(`[mbkauthe] No rows returned by schema query (expected). If you want to verify table creation, query the database separately.`);
|
|
20
20
|
}
|
|
21
21
|
} catch (err) {
|
|
22
22
|
const IGNORE_CODES = ["42710", "42P07"];
|
|
23
23
|
if (err && typeof err.code === "string" && IGNORE_CODES.includes(err.code)) {
|
|
24
|
-
console.warn(
|
|
24
|
+
console.warn(`[mbkauthe] Schema already exists (ignored):`, err.message);
|
|
25
25
|
} else {
|
|
26
|
-
console.error(
|
|
26
|
+
console.error(`[mbkauthe] Failed to apply schema:`, err);
|
|
27
27
|
process.exitCode = 1;
|
|
28
28
|
}
|
|
29
29
|
} finally {
|
package/lib/middleware/auth.js
CHANGED
|
@@ -5,6 +5,7 @@ import { clearSessionCookies, cachedCookieOptions, readAccountListFromCookie, en
|
|
|
5
5
|
import { ErrorCodes, createErrorResponse } from "../utils/errors.js";
|
|
6
6
|
import { hashApiToken } from "#config.js";
|
|
7
7
|
import { canAccessMethod } from "#config.js";
|
|
8
|
+
import { extractAuthorizationToken, timingSafeTokenMatch } from "../utils/timingSafeToken.js";
|
|
8
9
|
|
|
9
10
|
const IS_DEV = process.env.env === 'dev' || process.env.test === 'dev' || process.env.NODE_ENV === 'development';
|
|
10
11
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -30,6 +31,10 @@ function isJsonRequest(req) {
|
|
|
30
31
|
const url = (req.originalUrl || req.url || "").toLowerCase();
|
|
31
32
|
const path = (req.path || "").toLowerCase();
|
|
32
33
|
|
|
34
|
+
// Explicit opt-in: allow clients to force JSON responses via a minimal user-agent.
|
|
35
|
+
// Useful for health checks / lightweight clients that don't send Accept headers.
|
|
36
|
+
if (userAgent.trim() === "json") return true;
|
|
37
|
+
|
|
33
38
|
const isApiPath = url.startsWith("/mbkauthe/api/") || url.startsWith("/api/") || path.startsWith("/mbkauthe/api/") || path.startsWith("/api/");
|
|
34
39
|
const isAcceptJson = accept.includes("application/json") || accept.includes("json") || accept.includes("*/*");
|
|
35
40
|
|
|
@@ -88,7 +93,7 @@ async function validateTokenAuthentication(req) {
|
|
|
88
93
|
dblogin.query({
|
|
89
94
|
text: 'UPDATE "ApiTokens" SET "LastUsed" = NOW() WHERE id = $1',
|
|
90
95
|
values: [row.id]
|
|
91
|
-
}).catch(e => console.error(
|
|
96
|
+
}).catch(e => console.error(`[mbkauthe] Failed to update token usage:`, e));
|
|
92
97
|
|
|
93
98
|
return {
|
|
94
99
|
id: row.uid,
|
|
@@ -189,7 +194,7 @@ async function validateSession(req, res, next, strictTokenValidation = false) {
|
|
|
189
194
|
return res.status(401).json(createErrorResponse(401, errorCode));
|
|
190
195
|
|
|
191
196
|
} catch (err) {
|
|
192
|
-
console.error(
|
|
197
|
+
console.error(`[mbkauthe] Token validation error:`, err);
|
|
193
198
|
return res.status(500).json(createErrorResponse(500, ErrorCodes.INTERNAL_SERVER_ERROR));
|
|
194
199
|
}
|
|
195
200
|
}
|
|
@@ -197,8 +202,8 @@ async function validateSession(req, res, next, strictTokenValidation = false) {
|
|
|
197
202
|
// --- Fallback to Cookie Session ---
|
|
198
203
|
if (!req.session.user) {
|
|
199
204
|
if (IS_DEV) {
|
|
200
|
-
console.log(
|
|
201
|
-
console.log(
|
|
205
|
+
console.log(`[mbkauthe] User not authenticated`);
|
|
206
|
+
console.log(`[mbkauthe] req.session.user:`, req.session.user);
|
|
202
207
|
}
|
|
203
208
|
if (isJsonRequest(req)) {
|
|
204
209
|
return res.status(401).json(createErrorResponse(401, ErrorCodes.SESSION_NOT_FOUND));
|
|
@@ -318,7 +323,7 @@ async function validateSession(req, res, next, strictTokenValidation = false) {
|
|
|
318
323
|
|
|
319
324
|
next();
|
|
320
325
|
} catch (err) {
|
|
321
|
-
console.error(
|
|
326
|
+
console.error(`[mbkauthe] Session validation error:`, err);
|
|
322
327
|
res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
323
328
|
}
|
|
324
329
|
}
|
|
@@ -390,7 +395,7 @@ async function validateApiSession(req, res, next) {
|
|
|
390
395
|
|
|
391
396
|
next();
|
|
392
397
|
} catch (err) {
|
|
393
|
-
console.error(
|
|
398
|
+
console.error(`[mbkauthe] API session validation error:`, err);
|
|
394
399
|
return res.status(500).json(createErrorResponse(500, ErrorCodes.INTERNAL_SERVER_ERROR));
|
|
395
400
|
}
|
|
396
401
|
}
|
|
@@ -468,7 +473,7 @@ async function reloadSessionUser(req, res) {
|
|
|
468
473
|
const prof = await dblogin.query({ name: 'reload-get-fullname', text: 'SELECT "FullName" FROM "Users" WHERE "UserName" = $1 LIMIT 1', values: [row.UserName] });
|
|
469
474
|
if (prof.rows.length > 0 && prof.rows[0].FullName) req.session.user.fullname = prof.rows[0].FullName;
|
|
470
475
|
} catch (profileErr) {
|
|
471
|
-
console.error(
|
|
476
|
+
console.error(`[mbkauthe] Error fetching fullname during reload:`, profileErr);
|
|
472
477
|
}
|
|
473
478
|
}
|
|
474
479
|
|
|
@@ -483,12 +488,12 @@ async function reloadSessionUser(req, res) {
|
|
|
483
488
|
res.cookie('sessionId', encryptedSid, cachedCookieOptions);
|
|
484
489
|
}
|
|
485
490
|
} catch (cookieErr) {
|
|
486
|
-
console.error(
|
|
491
|
+
console.error(`[mbkauthe] Error syncing cookies during reload:`, cookieErr);
|
|
487
492
|
}
|
|
488
493
|
|
|
489
494
|
return true;
|
|
490
495
|
} catch (err) {
|
|
491
|
-
console.error(
|
|
496
|
+
console.error(`[mbkauthe] reloadSessionUser error:`, err);
|
|
492
497
|
return false;
|
|
493
498
|
}
|
|
494
499
|
}
|
|
@@ -497,7 +502,7 @@ const checkRolePermission = (requiredRoles, notAllowed) => {
|
|
|
497
502
|
return async (req, res, next) => {
|
|
498
503
|
try {
|
|
499
504
|
if (!req.session || !req.session.user || !req.session.user.id) {
|
|
500
|
-
console.log(
|
|
505
|
+
console.log(`[mbkauthe] User not authenticated`);
|
|
501
506
|
if (isJsonRequest(req)) {
|
|
502
507
|
return res.status(401).json(createErrorResponse(401, ErrorCodes.SESSION_NOT_FOUND));
|
|
503
508
|
}
|
|
@@ -514,7 +519,7 @@ const checkRolePermission = (requiredRoles, notAllowed) => {
|
|
|
514
519
|
const userRole = req.userRole;
|
|
515
520
|
|
|
516
521
|
// SuperAdmin bypasses all role checks
|
|
517
|
-
if(req.session.role === "SuperAdmin" || userRole === "SuperAdmin") {
|
|
522
|
+
if(req.session.user?.role === "SuperAdmin" || userRole === "SuperAdmin") {
|
|
518
523
|
return next();
|
|
519
524
|
}
|
|
520
525
|
|
|
@@ -556,7 +561,7 @@ const checkRolePermission = (requiredRoles, notAllowed) => {
|
|
|
556
561
|
|
|
557
562
|
next();
|
|
558
563
|
} catch (err) {
|
|
559
|
-
console.error(
|
|
564
|
+
console.error(`[mbkauthe] Permission check error:`, err);
|
|
560
565
|
res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
561
566
|
}
|
|
562
567
|
};
|
|
@@ -572,12 +577,12 @@ const validateSessionAndRole = (requiredRole, notAllowed, strictTokenValidation
|
|
|
572
577
|
|
|
573
578
|
const authenticate = (authentication) => {
|
|
574
579
|
return (req, res, next) => {
|
|
575
|
-
const token = req.headers["authorization"];
|
|
576
|
-
if (token
|
|
577
|
-
console.log(
|
|
580
|
+
const token = extractAuthorizationToken(req.headers?.authorization ?? req.headers?.["authorization"]);
|
|
581
|
+
if (timingSafeTokenMatch(token, authentication)) {
|
|
582
|
+
console.log(`[mbkauthe] Authentication successful`);
|
|
578
583
|
next();
|
|
579
584
|
} else {
|
|
580
|
-
console.log(
|
|
585
|
+
console.log(`[mbkauthe] Authentication failed`);
|
|
581
586
|
res.status(401).send("Unauthorized");
|
|
582
587
|
}
|
|
583
588
|
};
|
|
@@ -590,10 +595,15 @@ const strictValidateSessionAndRole = (requiredRole, notAllowed) => validateSessi
|
|
|
590
595
|
// Short aliases for convenience
|
|
591
596
|
const sessVal = validateSession;
|
|
592
597
|
const sessRole = validateSessionAndRole;
|
|
598
|
+
const roleChk = checkRolePermission;
|
|
599
|
+
|
|
600
|
+
// short strict validation aliases
|
|
601
|
+
const strictSessVal = strictValidateSession;
|
|
602
|
+
const strictSessRole = strictValidateSessionAndRole;
|
|
593
603
|
|
|
594
604
|
export {
|
|
595
605
|
validateSession, validateApiSession, checkRolePermission,
|
|
596
606
|
validateSessionAndRole, authenticate, reloadSessionUser,
|
|
597
607
|
strictValidateSession, strictValidateSessionAndRole,
|
|
598
|
-
sessVal, sessRole
|
|
608
|
+
sessVal, sessRole, roleChk, strictSessVal, strictSessRole
|
|
599
609
|
}
|
package/lib/middleware/index.js
CHANGED
|
@@ -114,13 +114,13 @@ export async function sessionRestorationMiddleware(req, res, next) {
|
|
|
114
114
|
req.session.user.fullname = profileRes.rows[0].FullName;
|
|
115
115
|
}
|
|
116
116
|
} catch (profileErr) {
|
|
117
|
-
console.error(
|
|
117
|
+
console.error(`[mbkauthe] Error fetching FullName during session restore:`, profileErr);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
} catch (err) {
|
|
123
|
-
console.error(
|
|
123
|
+
console.error(`[mbkauthe] Session restoration error:`, err);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
next();
|
package/lib/pool.js
CHANGED
|
@@ -34,9 +34,9 @@ attachDevQueryLogger(dblogin);
|
|
|
34
34
|
try {
|
|
35
35
|
const client = await dblogin.connect();
|
|
36
36
|
client.release();
|
|
37
|
-
console.log(
|
|
37
|
+
console.log(`[mbkauthe] Database connection pool established successfully.`);
|
|
38
38
|
} catch (err) {
|
|
39
|
-
console.error(
|
|
39
|
+
console.error(`[mbkauthe] Database connection error (pool):`, err);
|
|
40
40
|
}
|
|
41
41
|
})();
|
|
42
42
|
*/
|