From 87cccefddbbb9ef62b1150856af29bea6503345b Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 20 Apr 2024 19:04:33 +0800 Subject: [PATCH] :sparkles: New ticket ways --- .idea/dataSources.local.xml | 20 + .idea/dataSources.xml | 12 + .../74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml | 5716 +++++++++++++++++ .../_src_/database/hy_passport.gNOKQQ.meta | 1 + .../schema/public.abK9xQ.meta | 2 + .idea/workspace.xml | 96 +- pkg/database/migrator.go | 3 +- pkg/models/accounts.go | 5 +- pkg/models/auth.go | 71 +- pkg/models/clients.go | 2 +- pkg/security/challanges.go | 96 - pkg/security/factors.go | 27 - pkg/security/sessions.go | 165 - pkg/server/accounts_api.go | 2 +- pkg/server/auth_api.go | 145 + pkg/server/auth_middleware.go | 7 +- pkg/server/challanges_api.go | 140 - pkg/server/factors_api.go | 2 +- pkg/server/oauth_api.go | 21 +- pkg/server/security_api.go | 39 +- pkg/server/startup.go | 8 +- pkg/server/{userinfo.go => userinfo_api.go} | 0 pkg/services/accounts.go | 9 +- pkg/services/auth.go | 13 +- pkg/services/challanges.go | 26 - pkg/{security => services}/encryptor.go | 2 +- pkg/services/factors.go | 36 +- pkg/{security => services}/jwt.go | 2 +- .../{sessions.go => ticker_maintainer.go} | 17 +- pkg/services/ticket.go | 136 + pkg/services/ticket_queries.go | 29 + pkg/services/ticket_token.go | 98 + 32 files changed, 6280 insertions(+), 668 deletions(-) create mode 100644 .idea/dataSources.local.xml create mode 100644 .idea/dataSources.xml create mode 100644 .idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml create mode 100644 .idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ.meta create mode 100644 .idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ/schema/public.abK9xQ.meta delete mode 100644 pkg/security/challanges.go delete mode 100644 pkg/security/factors.go delete mode 100644 pkg/security/sessions.go create mode 100644 pkg/server/auth_api.go delete mode 100644 pkg/server/challanges_api.go rename pkg/server/{userinfo.go => userinfo_api.go} (100%) delete mode 100644 pkg/services/challanges.go rename pkg/{security => services}/encryptor.go (94%) rename pkg/{security => services}/jwt.go (99%) rename pkg/services/{sessions.go => ticker_maintainer.go} (80%) create mode 100644 pkg/services/ticket.go create mode 100644 pkg/services/ticket_queries.go create mode 100644 pkg/services/ticket_token.go diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml new file mode 100644 index 0000000..04919cb --- /dev/null +++ b/.idea/dataSources.local.xml @@ -0,0 +1,20 @@ + + + + + + " + + + master_key + postgres + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..cf4f20f --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/hy_passport + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml b/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml new file mode 100644 index 0000000..1daf5ad --- /dev/null +++ b/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml @@ -0,0 +1,5716 @@ + + + + + mdy + 1||-9223372036854775808|c|G +1||10|c|G +1||10|C|G +1||10|T|G +4||-9223372036854775808|c|G +4||10|c|G +4||10|C|G +4||10|T|G + 6258 + 16.2 + 1713083875 + true ACDT +true ACSST +false ACST +false ACT +false ACWST +true ADT +true AEDT +true AESST +false AEST +false AFT +true AKDT +false AKST +true ALMST +false ALMT +false AMST +false AMT +false ANAST +false ANAT +false ARST +false ART +false AST +true AWSST +false AWST +true AZOST +false AZOT +false AZST +false AZT +false Africa/Abidjan +false Africa/Accra +false Africa/Addis_Ababa +false Africa/Algiers +false Africa/Asmara +false Africa/Asmera +false Africa/Bamako +false Africa/Bangui +false Africa/Banjul +false Africa/Bissau +false Africa/Blantyre +false Africa/Brazzaville +false Africa/Bujumbura +false Africa/Cairo +false Africa/Casablanca +true Africa/Ceuta +false Africa/Conakry +false Africa/Dakar +false Africa/Dar_es_Salaam +false Africa/Djibouti +false Africa/Douala +false Africa/El_Aaiun +false Africa/Freetown +false Africa/Gaborone +false Africa/Harare +false Africa/Johannesburg +false Africa/Juba +false Africa/Kampala +false Africa/Khartoum +false Africa/Kigali +false Africa/Kinshasa +false Africa/Lagos +false Africa/Libreville +false Africa/Lome +false Africa/Luanda +false Africa/Lubumbashi +false Africa/Lusaka +false Africa/Malabo +false Africa/Maputo +false Africa/Maseru +false Africa/Mbabane +false Africa/Mogadishu +false Africa/Monrovia +false Africa/Nairobi +false Africa/Ndjamena +false Africa/Niamey +false Africa/Nouakchott +false Africa/Ouagadougou +false Africa/Porto-Novo +false Africa/Sao_Tome +false Africa/Timbuktu +false Africa/Tripoli +false Africa/Tunis +false Africa/Windhoek +true America/Adak +true America/Anchorage +false America/Anguilla +false America/Antigua +false America/Araguaina +false America/Argentina/Buenos_Aires +false America/Argentina/Catamarca +false America/Argentina/ComodRivadavia +false America/Argentina/Cordoba +false America/Argentina/Jujuy +false America/Argentina/La_Rioja +false America/Argentina/Mendoza +false America/Argentina/Rio_Gallegos +false America/Argentina/Salta +false America/Argentina/San_Juan +false America/Argentina/San_Luis +false America/Argentina/Tucuman +false America/Argentina/Ushuaia +false America/Aruba +false America/Asuncion +false America/Atikokan +true America/Atka +false America/Bahia +false America/Bahia_Banderas +false America/Barbados +false America/Belem +false America/Belize +false America/Blanc-Sablon +false America/Boa_Vista +false America/Bogota +true America/Boise +false America/Buenos_Aires +true America/Cambridge_Bay +false America/Campo_Grande +false America/Cancun +false America/Caracas +false America/Catamarca +false America/Cayenne +false America/Cayman +true America/Chicago +false America/Chihuahua +true America/Ciudad_Juarez +false America/Coral_Harbour +false America/Cordoba +false America/Costa_Rica +false America/Creston +false America/Cuiaba +false America/Curacao +false America/Danmarkshavn +false America/Dawson +false America/Dawson_Creek +true America/Denver +true America/Detroit +false America/Dominica +true America/Edmonton +false America/Eirunepe +false America/El_Salvador +true America/Ensenada +false America/Fort_Nelson +true America/Fort_Wayne +false America/Fortaleza +true America/Glace_Bay +true America/Godthab +true America/Goose_Bay +true America/Grand_Turk +false America/Grenada +false America/Guadeloupe +false America/Guatemala +false America/Guayaquil +false America/Guyana +true America/Halifax +true America/Havana +false America/Hermosillo +true America/Indiana/Indianapolis +true America/Indiana/Knox +true America/Indiana/Marengo +true America/Indiana/Petersburg +true America/Indiana/Tell_City +true America/Indiana/Vevay +true America/Indiana/Vincennes +true America/Indiana/Winamac +true America/Indianapolis +true America/Inuvik +true America/Iqaluit +false America/Jamaica +false America/Jujuy +true America/Juneau +true America/Kentucky/Louisville +true America/Kentucky/Monticello +true America/Knox_IN +false America/Kralendijk +false America/La_Paz +false America/Lima +true America/Los_Angeles +true America/Louisville +false America/Lower_Princes +false America/Maceio +false America/Managua +false America/Manaus +false America/Marigot +false America/Martinique +true America/Matamoros +false America/Mazatlan +false America/Mendoza +true America/Menominee +false America/Merida +true America/Metlakatla +false America/Mexico_City +true America/Miquelon +true America/Moncton +false America/Monterrey +false America/Montevideo +true America/Montreal +false America/Montserrat +true America/Nassau +true America/New_York +true America/Nipigon +true America/Nome +false America/Noronha +true America/North_Dakota/Beulah +true America/North_Dakota/Center +true America/North_Dakota/New_Salem +true America/Nuuk +true America/Ojinaga +false America/Panama +true America/Pangnirtung +false America/Paramaribo +false America/Phoenix +true America/Port-au-Prince +false America/Port_of_Spain +false America/Porto_Acre +false America/Porto_Velho +false America/Puerto_Rico +false America/Punta_Arenas +true America/Rainy_River +true America/Rankin_Inlet +false America/Recife +false America/Regina +true America/Resolute +false America/Rio_Branco +false America/Rosario +true America/Santa_Isabel +false America/Santarem +false America/Santiago +false America/Santo_Domingo +false America/Sao_Paulo +true America/Scoresbysund +true America/Shiprock +true America/Sitka +false America/St_Barthelemy +true America/St_Johns +false America/St_Kitts +false America/St_Lucia +false America/St_Thomas +false America/St_Vincent +false America/Swift_Current +false America/Tegucigalpa +true America/Thule +true America/Thunder_Bay +true America/Tijuana +true America/Toronto +false America/Tortola +true America/Vancouver +false America/Virgin +false America/Whitehorse +true America/Winnipeg +true America/Yakutat +true America/Yellowknife +false Antarctica/Casey +false Antarctica/Davis +false Antarctica/DumontDUrville +false Antarctica/Macquarie +false Antarctica/Mawson +false Antarctica/McMurdo +false Antarctica/Palmer +false Antarctica/Rothera +false Antarctica/South_Pole +false Antarctica/Syowa +true Antarctica/Troll +false Antarctica/Vostok +true Arctic/Longyearbyen +false Asia/Aden +false Asia/Almaty +false Asia/Amman +false Asia/Anadyr +false Asia/Aqtau +false Asia/Aqtobe +false Asia/Ashgabat +false Asia/Ashkhabad +false Asia/Atyrau +false Asia/Baghdad +false Asia/Bahrain +false Asia/Baku +false Asia/Bangkok +false Asia/Barnaul +true Asia/Beirut +false Asia/Bishkek +false Asia/Brunei +false Asia/Calcutta +false Asia/Chita +false Asia/Choibalsan +false Asia/Chongqing +false Asia/Chungking +false Asia/Colombo +false Asia/Dacca +false Asia/Damascus +false Asia/Dhaka +false Asia/Dili +false Asia/Dubai +false Asia/Dushanbe +true Asia/Famagusta +true Asia/Gaza +false Asia/Harbin +true Asia/Hebron +false Asia/Ho_Chi_Minh +false Asia/Hong_Kong +false Asia/Hovd +false Asia/Irkutsk +false Asia/Istanbul +false Asia/Jakarta +false Asia/Jayapura +true Asia/Jerusalem +false Asia/Kabul +false Asia/Kamchatka +false Asia/Karachi +false Asia/Kashgar +false Asia/Kathmandu +false Asia/Katmandu +false Asia/Khandyga +false Asia/Kolkata +false Asia/Krasnoyarsk +false Asia/Kuala_Lumpur +false Asia/Kuching +false Asia/Kuwait +false Asia/Macao +false Asia/Macau +false Asia/Magadan +false Asia/Makassar +false Asia/Manila +false Asia/Muscat +true Asia/Nicosia +false Asia/Novokuznetsk +false Asia/Novosibirsk +false Asia/Omsk +false Asia/Oral +false Asia/Phnom_Penh +false Asia/Pontianak +false Asia/Pyongyang +false Asia/Qatar +false Asia/Qostanay +false Asia/Qyzylorda +false Asia/Rangoon +false Asia/Riyadh +false Asia/Saigon +false Asia/Sakhalin +false Asia/Samarkand +false Asia/Seoul +false Asia/Shanghai +false Asia/Singapore +false Asia/Srednekolymsk +false Asia/Taipei +false Asia/Tashkent +false Asia/Tbilisi +false Asia/Tehran +true Asia/Tel_Aviv +false Asia/Thimbu +false Asia/Thimphu +false Asia/Tokyo +false Asia/Tomsk +false Asia/Ujung_Pandang +false Asia/Ulaanbaatar +false Asia/Ulan_Bator +false Asia/Urumqi +false Asia/Ust-Nera +false Asia/Vientiane +false Asia/Vladivostok +false Asia/Yakutsk +false Asia/Yangon +false Asia/Yekaterinburg +false Asia/Yerevan +true Atlantic/Azores +true Atlantic/Bermuda +true Atlantic/Canary +false Atlantic/Cape_Verde +true Atlantic/Faeroe +true Atlantic/Faroe +true Atlantic/Jan_Mayen +true Atlantic/Madeira +false Atlantic/Reykjavik +false Atlantic/South_Georgia +false Atlantic/St_Helena +false Atlantic/Stanley +false Australia/ACT +false Australia/Adelaide +false Australia/Brisbane +false Australia/Broken_Hill +false Australia/Canberra +false Australia/Currie +false Australia/Darwin +false Australia/Eucla +false Australia/Hobart +false Australia/LHI +false Australia/Lindeman +false Australia/Lord_Howe +false Australia/Melbourne +false Australia/NSW +false Australia/North +false Australia/Perth +false Australia/Queensland +false Australia/South +false Australia/Sydney +false Australia/Tasmania +false Australia/Victoria +false Australia/West +false Australia/Yancowinna +true BDST +false BDT +false BNT +false BORT +false BOT +false BRA +true BRST +false BRT +true BST +false BTT +false Brazil/Acre +false Brazil/DeNoronha +false Brazil/East +false Brazil/West +true CADT +false CAST +false CCT +true CDT +true CEST +false CET +true CETDST +true CHADT +false CHAST +false CHUT +false CKT +true CLST +false CLT +false COT +false CST +true CST6CDT +false CXT +true Canada/Atlantic +true Canada/Central +true Canada/Eastern +true Canada/Mountain +true Canada/Newfoundland +true Canada/Pacific +false Canada/Saskatchewan +false Canada/Yukon +false Chile/Continental +false Chile/EasterIsland +true Cuba +false DAVT +false DDUT +false EASST +false EAST +false EAT +true EDT +true EEST +false EET +true EETDST +true EGST +false EGT +false EST +true EST5EDT +false Egypt +false Eire +false Etc/GMT +false Etc/GMT+0 +false Etc/GMT+1 +false Etc/GMT+10 +false Etc/GMT+11 +false Etc/GMT+12 +false Etc/GMT+2 +false Etc/GMT+3 +false Etc/GMT+4 +false Etc/GMT+5 +false Etc/GMT+6 +false Etc/GMT+7 +false Etc/GMT+8 +false Etc/GMT+9 +false Etc/GMT-0 +false Etc/GMT-1 +false Etc/GMT-10 +false Etc/GMT-11 +false Etc/GMT-12 +false Etc/GMT-13 +false Etc/GMT-14 +false Etc/GMT-2 +false Etc/GMT-3 +false Etc/GMT-4 +false Etc/GMT-5 +false Etc/GMT-6 +false Etc/GMT-7 +false Etc/GMT-8 +false Etc/GMT-9 +false Etc/GMT0 +false Etc/Greenwich +false Etc/UCT +false Etc/UTC +false Etc/Universal +false Etc/Zulu +true Europe/Amsterdam +true Europe/Andorra +false Europe/Astrakhan +true Europe/Athens +true Europe/Belfast +true Europe/Belgrade +true Europe/Berlin +true Europe/Bratislava +true Europe/Brussels +true Europe/Bucharest +true Europe/Budapest +true Europe/Busingen +true Europe/Chisinau +true Europe/Copenhagen +false Europe/Dublin +true Europe/Gibraltar +true Europe/Guernsey +true Europe/Helsinki +true Europe/Isle_of_Man +false Europe/Istanbul +true Europe/Jersey +false Europe/Kaliningrad +true Europe/Kiev +false Europe/Kirov +true Europe/Kyiv +true Europe/Lisbon +true Europe/Ljubljana +true Europe/London +true Europe/Luxembourg +true Europe/Madrid +true Europe/Malta +true Europe/Mariehamn +false Europe/Minsk +true Europe/Monaco +false Europe/Moscow +true Europe/Nicosia +true Europe/Oslo +true Europe/Paris +true Europe/Podgorica +true Europe/Prague +true Europe/Riga +true Europe/Rome +false Europe/Samara +true Europe/San_Marino +true Europe/Sarajevo +false Europe/Saratov +false Europe/Simferopol +true Europe/Skopje +true Europe/Sofia +true Europe/Stockholm +true Europe/Tallinn +true Europe/Tirane +true Europe/Tiraspol +false Europe/Ulyanovsk +true Europe/Uzhgorod +true Europe/Vaduz +true Europe/Vatican +true Europe/Vienna +true Europe/Vilnius +false Europe/Volgograd +true Europe/Warsaw +true Europe/Zagreb +true Europe/Zaporozhye +true Europe/Zurich +false FET +true FJST +false FJT +false FKST +false FKT +true FNST +false FNT +false Factory +false GALT +false GAMT +true GB +true GB-Eire +false GEST +false GET +false GFT +false GILT +false GMT +false GMT+0 +false GMT-0 +false GMT0 +false GYT +false Greenwich +false HKT +false HST +false Hongkong +false ICT +true IDT +false IOT +false IRKST +false IRKT +false IRT +false IST +false Iceland +false Indian/Antananarivo +false Indian/Chagos +false Indian/Christmas +false Indian/Cocos +false Indian/Comoro +false Indian/Kerguelen +false Indian/Mahe +false Indian/Maldives +false Indian/Mauritius +false Indian/Mayotte +false Indian/Reunion +false Iran +true Israel +false JAYT +false JST +false Jamaica +false Japan +true KDT +true KGST +false KGT +false KOST +false KRAST +false KRAT +false KST +false Kwajalein +false LHDT +false LHST +false LIGT +false LINT +false LKT +false Libya +false MAGST +false MAGT +false MART +false MAWT +true MDT +true MEST +true MESZ +true MET +true METDST +false MEZ +false MHT +false MMT +false MPT +true MSD +false MSK +false MST +true MST7MDT +true MUST +false MUT +false MVT +false MYT +true Mexico/BajaNorte +false Mexico/BajaSur +false Mexico/General +true NDT +false NFT +false NOVST +false NOVT +false NPT +false NST +false NUT +false NZ +false NZ-CHAT +true NZDT +false NZST +false NZT +true Navajo +false OMSST +false OMST +true PDT +false PET +false PETST +false PETT +false PGT +false PHT +true PKST +false PKT +true PMDT +false PMST +false PONT +false PRC +false PST +true PST8PDT +false PWT +true PYST +false PYT +false Pacific/Apia +false Pacific/Auckland +false Pacific/Bougainville +false Pacific/Chatham +false Pacific/Chuuk +false Pacific/Easter +false Pacific/Efate +false Pacific/Enderbury +false Pacific/Fakaofo +false Pacific/Fiji +false Pacific/Funafuti +false Pacific/Galapagos +false Pacific/Gambier +false Pacific/Guadalcanal +false Pacific/Guam +false Pacific/Honolulu +false Pacific/Johnston +false Pacific/Kanton +false Pacific/Kiritimati +false Pacific/Kosrae +false Pacific/Kwajalein +false Pacific/Majuro +false Pacific/Marquesas +false Pacific/Midway +false Pacific/Nauru +false Pacific/Niue +false Pacific/Norfolk +false Pacific/Noumea +false Pacific/Pago_Pago +false Pacific/Palau +false Pacific/Pitcairn +false Pacific/Pohnpei +false Pacific/Ponape +false Pacific/Port_Moresby +false Pacific/Rarotonga +false Pacific/Saipan +false Pacific/Samoa +false Pacific/Tahiti +false Pacific/Tarawa +false Pacific/Tongatapu +false Pacific/Truk +false Pacific/Wake +false Pacific/Wallis +false Pacific/Yap +true Poland +true Portugal +false RET +false ROC +false ROK +true SADT +false SAST +false SCT +false SGT +false Singapore +false TAHT +false TFT +false TJT +false TKT +false TMT +false TOT +false TRUT +false TVT +false Turkey +false UCT +true ULAST +false ULAT +true US/Alaska +true US/Aleutian +false US/Arizona +true US/Central +true US/East-Indiana +true US/Eastern +false US/Hawaii +true US/Indiana-Starke +true US/Michigan +true US/Mountain +true US/Pacific +false US/Samoa +false UT +false UTC +true UYST +false UYT +true UZST +false UZT +false Universal +false VET +false VLAST +false VLAT +false VOLT +false VUT +false W-SU +true WADT +false WAKT +false WAST +false WAT +true WDT +true WET +true WETDST +false WFT +true WGST +false WGT +false XJT +false YAKST +false YAKT +false YAPT +true YEKST +false YEKT +false Z +false Zulu + + + + 1 + 11||10|C|G +11||-9223372036854775808|U|G +11||10|U|G +2200||6171|C|G +2200||-9223372036854775808|U|G +2200||6171|U|G +13474||10|C|G +13474||-9223372036854775808|U|G +13474||10|U|G + 6258 + 37312 + postgres + + + default administrative connection database + 5 + littlesheep + + + 19304 + postgres + + + 20328 + postgres + + + 37162 + postgres + + + 1 + 1 + 1 + 1 + 10 + 1 + 1 + + + 6171 + + + 6181 + + + 6182 + + + 3373 + 3374 +3375 +3377 + + + 3374 + + + 3375 + + + 3377 + + + 4569 + + + 4570 + + + 4571 + + + 4200 + + + 4544 + + + 4550 + + + 6304 + + + 1 + 18757 + 1 + + + 1663 + 1 + littlesheep + + + 1664 + 1 + littlesheep + + + block range index (BRIN) access method + 3580 + 1 + index + 335 + brinhandler + pg_catalog + + + b-tree index access method + 403 + 1 + index + 330 + bthandler + pg_catalog + + + GIN index access method + 2742 + 1 + index + 333 + ginhandler + pg_catalog + + + GiST index access method + 783 + 1 + index + 332 + gisthandler + pg_catalog + + + hash index access method + 405 + 1 + index + 331 + hashhandler + pg_catalog + + + heap table access method + 2 + 1 + table + 3 + heap_tableam_handler + pg_catalog + + + SP-GiST index access method + 4000 + 1 + index + 334 + spghandler + pg_catalog + + + explicit + function + 10035 + 1 + 2558 + int4 + pg_catalog + 16 + bool + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10201 + 1 + 2971 + text + pg_catalog + 16 + bool + pg_catalog + 1042 + bpchar + pg_catalog + + + assignment + function + 10191 + 1 + 2971 + text + pg_catalog + 16 + bool + pg_catalog + 25 + text + pg_catalog + + + assignment + function + 10196 + 1 + 2971 + text + pg_catalog + 16 + bool + pg_catalog + 1043 + varchar + pg_catalog + + + explicit + function + 10143 + 1 + 77 + int4 + pg_catalog + 18 + char + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10133 + 1 + 946 + text + pg_catalog + 18 + char + pg_catalog + 1043 + varchar + pg_catalog + + + implicit + function + 10131 + 1 + 946 + text + pg_catalog + 18 + char + pg_catalog + 25 + text + pg_catalog + + + assignment + function + 10132 + 1 + 860 + bpchar + pg_catalog + 18 + char + pg_catalog + 1042 + bpchar + pg_catalog + + + assignment + function + 10135 + 1 + 408 + bpchar + pg_catalog + 19 + name + pg_catalog + 1042 + bpchar + pg_catalog + + + implicit + function + 10134 + 1 + 406 + text + pg_catalog + 19 + name + pg_catalog + 25 + text + pg_catalog + + + assignment + function + 10136 + 1 + 1401 + varchar + pg_catalog + 19 + name + pg_catalog + 1043 + varchar + pg_catalog + + + implicit + function + 10090 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 2206 + regtype + pg_catalog + + + implicit + function + 10060 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 2203 + regoper + pg_catalog + + + implicit + function + 10003 + 1 + 482 + float8 + pg_catalog + 20 + int8 + pg_catalog + 701 + float8 + pg_catalog + + + implicit + function + 10069 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 2204 + regoperator + pg_catalog + + + assignment + function + 10001 + 1 + 480 + int4 + pg_catalog + 20 + int8 + pg_catalog + 23 + int4 + pg_catalog + + + implicit + function + 10044 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 24 + regproc + pg_catalog + + + implicit + function + 10113 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 4096 + regrole + pg_catalog + + + implicit + function + 10120 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 4089 + regnamespace + pg_catalog + + + implicit + function + 10002 + 1 + 652 + float4 + pg_catalog + 20 + int8 + pg_catalog + 700 + float4 + pg_catalog + + + implicit + function + 10104 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 3769 + regdictionary + pg_catalog + + + implicit + function + 10083 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 4191 + regcollation + pg_catalog + + + assignment + function + 10033 + 1 + 3812 + money + pg_catalog + 20 + int8 + pg_catalog + 790 + money + pg_catalog + + + implicit + function + 10037 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 26 + oid + pg_catalog + + + implicit + function + 10097 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 3734 + regconfig + pg_catalog + + + assignment + function + 10000 + 1 + 714 + int2 + pg_catalog + 20 + int8 + pg_catalog + 21 + int2 + pg_catalog + + + explicit + function + 10185 + 1 + 2075 + bit + pg_catalog + 20 + int8 + pg_catalog + 1560 + bit + pg_catalog + + + implicit + function + 10004 + 1 + 1781 + numeric + pg_catalog + 20 + int8 + pg_catalog + 1700 + numeric + pg_catalog + + + implicit + function + 10053 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 2202 + regprocedure + pg_catalog + + + implicit + function + 10076 + 1 + 1287 + oid + pg_catalog + 20 + int8 + pg_catalog + 2205 + regclass + pg_catalog + + + implicit + function + 10045 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 24 + regproc + pg_catalog + + + implicit + function + 10091 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 2206 + regtype + pg_catalog + + + implicit + function + 10084 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 4191 + regcollation + pg_catalog + + + implicit + function + 10070 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 2204 + regoperator + pg_catalog + + + implicit + function + 10038 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 26 + oid + pg_catalog + + + implicit + function + 10009 + 1 + 1782 + numeric + pg_catalog + 21 + int2 + pg_catalog + 1700 + numeric + pg_catalog + + + implicit + function + 10077 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 2205 + regclass + pg_catalog + + + implicit + function + 10006 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 23 + int4 + pg_catalog + + + implicit + function + 10054 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 2202 + regprocedure + pg_catalog + + + implicit + function + 10007 + 1 + 236 + float4 + pg_catalog + 21 + int2 + pg_catalog + 700 + float4 + pg_catalog + + + implicit + function + 10005 + 1 + 754 + int8 + pg_catalog + 21 + int2 + pg_catalog + 20 + int8 + pg_catalog + + + implicit + function + 10114 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 4096 + regrole + pg_catalog + + + implicit + function + 10008 + 1 + 235 + float8 + pg_catalog + 21 + int2 + pg_catalog + 701 + float8 + pg_catalog + + + implicit + function + 10105 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 3769 + regdictionary + pg_catalog + + + implicit + function + 10121 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 4089 + regnamespace + pg_catalog + + + implicit + function + 10061 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 2203 + regoper + pg_catalog + + + implicit + function + 10098 + 1 + 313 + int4 + pg_catalog + 21 + int2 + pg_catalog + 3734 + regconfig + pg_catalog + + + implicit + binary + 10078 + 1 + 23 + int4 + pg_catalog + 2205 + regclass + pg_catalog + + + implicit + binary + 10085 + 1 + 23 + int4 + pg_catalog + 4191 + regcollation + pg_catalog + + + implicit + binary + 10115 + 1 + 23 + int4 + pg_catalog + 4096 + regrole + pg_catalog + + + explicit + function + 10144 + 1 + 78 + char + pg_catalog + 23 + int4 + pg_catalog + 18 + char + pg_catalog + + + implicit + binary + 10122 + 1 + 23 + int4 + pg_catalog + 4089 + regnamespace + pg_catalog + + + implicit + function + 10010 + 1 + 481 + int8 + pg_catalog + 23 + int4 + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10106 + 1 + 23 + int4 + pg_catalog + 3769 + regdictionary + pg_catalog + + + implicit + binary + 10099 + 1 + 23 + int4 + pg_catalog + 3734 + regconfig + pg_catalog + + + assignment + function + 10011 + 1 + 314 + int2 + pg_catalog + 23 + int4 + pg_catalog + 21 + int2 + pg_catalog + + + implicit + binary + 10092 + 1 + 23 + int4 + pg_catalog + 2206 + regtype + pg_catalog + + + implicit + binary + 10071 + 1 + 23 + int4 + pg_catalog + 2204 + regoperator + pg_catalog + + + implicit + binary + 10062 + 1 + 23 + int4 + pg_catalog + 2203 + regoper + pg_catalog + + + implicit + binary + 10046 + 1 + 23 + int4 + pg_catalog + 24 + regproc + pg_catalog + + + implicit + binary + 10055 + 1 + 23 + int4 + pg_catalog + 2202 + regprocedure + pg_catalog + + + explicit + function + 10034 + 1 + 2557 + bool + pg_catalog + 23 + int4 + pg_catalog + 16 + bool + pg_catalog + + + implicit + function + 10014 + 1 + 1740 + numeric + pg_catalog + 23 + int4 + pg_catalog + 1700 + numeric + pg_catalog + + + implicit + binary + 10039 + 1 + 23 + int4 + pg_catalog + 26 + oid + pg_catalog + + + explicit + function + 10186 + 1 + 1683 + bit + pg_catalog + 23 + int4 + pg_catalog + 1560 + bit + pg_catalog + + + implicit + function + 10012 + 1 + 318 + float4 + pg_catalog + 23 + int4 + pg_catalog + 700 + float4 + pg_catalog + + + implicit + function + 10013 + 1 + 316 + float8 + pg_catalog + 23 + int4 + pg_catalog + 701 + float8 + pg_catalog + + + assignment + function + 10032 + 1 + 3811 + money + pg_catalog + 23 + int4 + pg_catalog + 790 + money + pg_catalog + + + assignment + binary + 10048 + 1 + 24 + regproc + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10047 + 1 + 1288 + int8 + pg_catalog + 24 + regproc + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10043 + 1 + 24 + regproc + pg_catalog + 26 + oid + pg_catalog + + + implicit + binary + 10049 + 1 + 24 + regproc + pg_catalog + 2202 + regprocedure + pg_catalog + + + implicit + binary + 10125 + 1 + 25 + text + pg_catalog + 1042 + bpchar + pg_catalog + + + implicit + function + 10140 + 1 + 407 + name + pg_catalog + 25 + text + pg_catalog + 19 + name + pg_catalog + + + assignment + function + 10137 + 1 + 944 + char + pg_catalog + 25 + text + pg_catalog + 18 + char + pg_catalog + + + implicit + binary + 10126 + 1 + 25 + text + pg_catalog + 1043 + varchar + pg_catalog + + + explicit + function + 10193 + 1 + 2896 + xml + pg_catalog + 25 + text + pg_catalog + 142 + xml + pg_catalog + + + implicit + function + 10109 + 1 + 1079 + regclass + pg_catalog + 25 + text + pg_catalog + 2205 + regclass + pg_catalog + + + implicit + binary + 10074 + 1 + 26 + oid + pg_catalog + 2205 + regclass + pg_catalog + + + implicit + binary + 10051 + 1 + 26 + oid + pg_catalog + 2202 + regprocedure + pg_catalog + + + implicit + binary + 10095 + 1 + 26 + oid + pg_catalog + 3734 + regconfig + pg_catalog + + + implicit + binary + 10058 + 1 + 26 + oid + pg_catalog + 2203 + regoper + pg_catalog + + + implicit + binary + 10081 + 1 + 26 + oid + pg_catalog + 4191 + regcollation + pg_catalog + + + implicit + binary + 10067 + 1 + 26 + oid + pg_catalog + 2204 + regoperator + pg_catalog + + + implicit + binary + 10042 + 1 + 26 + oid + pg_catalog + 24 + regproc + pg_catalog + + + assignment + function + 10040 + 1 + 1288 + int8 + pg_catalog + 26 + oid + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10111 + 1 + 26 + oid + pg_catalog + 4096 + regrole + pg_catalog + + + implicit + binary + 10102 + 1 + 26 + oid + pg_catalog + 3769 + regdictionary + pg_catalog + + + implicit + binary + 10088 + 1 + 26 + oid + pg_catalog + 2206 + regtype + pg_catalog + + + assignment + binary + 10041 + 1 + 26 + oid + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10118 + 1 + 26 + oid + pg_catalog + 4089 + regnamespace + pg_catalog + + + assignment + io + 10214 + 1 + 114 + json + pg_catalog + 3802 + jsonb + pg_catalog + + + assignment + binary + 10202 + 1 + 142 + xml + pg_catalog + 1042 + bpchar + pg_catalog + + + assignment + binary + 10197 + 1 + 142 + xml + pg_catalog + 1043 + varchar + pg_catalog + + + assignment + binary + 10192 + 1 + 142 + xml + pg_catalog + 25 + text + pg_catalog + + + implicit + binary + 10145 + 1 + 194 + pg_node_tree + pg_catalog + 25 + text + pg_catalog + + + assignment + function + 10165 + 1 + 4091 + box + pg_catalog + 600 + point + pg_catalog + 603 + box + pg_catalog + + + explicit + function + 10166 + 1 + 1532 + point + pg_catalog + 601 + lseg + pg_catalog + 600 + point + pg_catalog + + + assignment + function + 10167 + 1 + 1449 + polygon + pg_catalog + 602 + path + pg_catalog + 604 + polygon + pg_catalog + + + explicit + function + 10168 + 1 + 1534 + point + pg_catalog + 603 + box + pg_catalog + 600 + point + pg_catalog + + + explicit + function + 10171 + 1 + 1479 + circle + pg_catalog + 603 + box + pg_catalog + 718 + circle + pg_catalog + + + explicit + function + 10169 + 1 + 1541 + lseg + pg_catalog + 603 + box + pg_catalog + 601 + lseg + pg_catalog + + + assignment + function + 10170 + 1 + 1448 + polygon + pg_catalog + 603 + box + pg_catalog + 604 + polygon + pg_catalog + + + explicit + function + 10172 + 1 + 1540 + point + pg_catalog + 604 + polygon + pg_catalog + 600 + point + pg_catalog + + + explicit + function + 10175 + 1 + 1474 + circle + pg_catalog + 604 + polygon + pg_catalog + 718 + circle + pg_catalog + + + explicit + function + 10174 + 1 + 1446 + box + pg_catalog + 604 + polygon + pg_catalog + 603 + box + pg_catalog + + + assignment + function + 10173 + 1 + 1447 + path + pg_catalog + 604 + polygon + pg_catalog + 602 + path + pg_catalog + + + assignment + function + 10194 + 1 + 730 + text + pg_catalog + 650 + cidr + pg_catalog + 1043 + varchar + pg_catalog + + + assignment + function + 10199 + 1 + 730 + text + pg_catalog + 650 + cidr + pg_catalog + 1042 + bpchar + pg_catalog + + + assignment + function + 10189 + 1 + 730 + text + pg_catalog + 650 + cidr + pg_catalog + 25 + text + pg_catalog + + + implicit + binary + 10181 + 1 + 650 + cidr + pg_catalog + 869 + inet + pg_catalog + + + assignment + function + 10016 + 1 + 238 + int2 + pg_catalog + 700 + float4 + pg_catalog + 21 + int2 + pg_catalog + + + assignment + function + 10015 + 1 + 653 + int8 + pg_catalog + 700 + float4 + pg_catalog + 20 + int8 + pg_catalog + + + implicit + function + 10018 + 1 + 311 + float8 + pg_catalog + 700 + float4 + pg_catalog + 701 + float8 + pg_catalog + + + assignment + function + 10019 + 1 + 1742 + numeric + pg_catalog + 700 + float4 + pg_catalog + 1700 + numeric + pg_catalog + + + assignment + function + 10017 + 1 + 319 + int4 + pg_catalog + 700 + float4 + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10024 + 1 + 1743 + numeric + pg_catalog + 701 + float8 + pg_catalog + 1700 + numeric + pg_catalog + + + assignment + function + 10020 + 1 + 483 + int8 + pg_catalog + 701 + float8 + pg_catalog + 20 + int8 + pg_catalog + + + assignment + function + 10021 + 1 + 237 + int2 + pg_catalog + 701 + float8 + pg_catalog + 21 + int2 + pg_catalog + + + assignment + function + 10022 + 1 + 317 + int4 + pg_catalog + 701 + float8 + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10023 + 1 + 312 + float4 + pg_catalog + 701 + float8 + pg_catalog + 700 + float4 + pg_catalog + + + explicit + function + 10178 + 1 + 1544 + polygon + pg_catalog + 718 + circle + pg_catalog + 604 + polygon + pg_catalog + + + explicit + function + 10176 + 1 + 1416 + point + pg_catalog + 718 + circle + pg_catalog + 600 + point + pg_catalog + + + explicit + function + 10177 + 1 + 1480 + box + pg_catalog + 718 + circle + pg_catalog + 603 + box + pg_catalog + + + implicit + function + 10180 + 1 + 4124 + macaddr + pg_catalog + 774 + macaddr8 + pg_catalog + 829 + macaddr + pg_catalog + + + assignment + function + 10030 + 1 + 3823 + numeric + pg_catalog + 790 + money + pg_catalog + 1700 + numeric + pg_catalog + + + implicit + function + 10179 + 1 + 4123 + macaddr8 + pg_catalog + 829 + macaddr + pg_catalog + 774 + macaddr8 + pg_catalog + + + assignment + function + 10195 + 1 + 730 + text + pg_catalog + 869 + inet + pg_catalog + 1043 + varchar + pg_catalog + + + assignment + function + 10190 + 1 + 730 + text + pg_catalog + 869 + inet + pg_catalog + 25 + text + pg_catalog + + + assignment + function + 10182 + 1 + 1715 + cidr + pg_catalog + 869 + inet + pg_catalog + 650 + cidr + pg_catalog + + + assignment + function + 10200 + 1 + 730 + text + pg_catalog + 869 + inet + pg_catalog + 1042 + bpchar + pg_catalog + + + implicit + function + 10204 + 1 + 668 + bpchar + pg_catalog + 1042 + bpchar + pg_catalog + 1042 + bpchar + pg_catalog + + + implicit + function + 10128 + 1 + 401 + text + pg_catalog + 1042 + bpchar + pg_catalog + 1043 + varchar + pg_catalog + + + explicit + function + 10203 + 1 + 2896 + xml + pg_catalog + 1042 + bpchar + pg_catalog + 142 + xml + pg_catalog + + + implicit + function + 10127 + 1 + 401 + text + pg_catalog + 1042 + bpchar + pg_catalog + 25 + text + pg_catalog + + + assignment + function + 10138 + 1 + 944 + char + pg_catalog + 1042 + bpchar + pg_catalog + 18 + char + pg_catalog + + + implicit + function + 10141 + 1 + 409 + name + pg_catalog + 1042 + bpchar + pg_catalog + 19 + name + pg_catalog + + + implicit + binary + 10129 + 1 + 1043 + varchar + pg_catalog + 25 + text + pg_catalog + + + implicit + function + 10142 + 1 + 1400 + name + pg_catalog + 1043 + varchar + pg_catalog + 19 + name + pg_catalog + + + implicit + binary + 10130 + 1 + 1043 + varchar + pg_catalog + 1042 + bpchar + pg_catalog + + + explicit + function + 10198 + 1 + 2896 + xml + pg_catalog + 1043 + varchar + pg_catalog + 142 + xml + pg_catalog + + + implicit + function + 10110 + 1 + 1079 + regclass + pg_catalog + 1043 + varchar + pg_catalog + 2205 + regclass + pg_catalog + + + implicit + function + 10205 + 1 + 669 + varchar + pg_catalog + 1043 + varchar + pg_catalog + 1043 + varchar + pg_catalog + + + assignment + function + 10139 + 1 + 944 + char + pg_catalog + 1043 + varchar + pg_catalog + 18 + char + pg_catalog + + + implicit + function + 10152 + 1 + 2024 + timestamp + pg_catalog + 1082 + date + pg_catalog + 1114 + timestamp + pg_catalog + + + implicit + function + 10153 + 1 + 1174 + timestamptz + pg_catalog + 1082 + date + pg_catalog + 1184 + timestamptz + pg_catalog + + + implicit + function + 10206 + 1 + 1968 + time + pg_catalog + 1083 + time + pg_catalog + 1083 + time + pg_catalog + + + implicit + function + 10155 + 1 + 2047 + timetz + pg_catalog + 1083 + time + pg_catalog + 1266 + timetz + pg_catalog + + + implicit + function + 10154 + 1 + 1370 + interval + pg_catalog + 1083 + time + pg_catalog + 1186 + interval + pg_catalog + + + implicit + function + 10158 + 1 + 2028 + timestamptz + pg_catalog + 1114 + timestamp + pg_catalog + 1184 + timestamptz + pg_catalog + + + assignment + function + 10156 + 1 + 2029 + date + pg_catalog + 1114 + timestamp + pg_catalog + 1082 + date + pg_catalog + + + assignment + function + 10157 + 1 + 1316 + time + pg_catalog + 1114 + timestamp + pg_catalog + 1083 + time + pg_catalog + + + implicit + function + 10207 + 1 + 1961 + timestamp + pg_catalog + 1114 + timestamp + pg_catalog + 1114 + timestamp + pg_catalog + + + assignment + function + 10159 + 1 + 1178 + date + pg_catalog + 1184 + timestamptz + pg_catalog + 1082 + date + pg_catalog + + + assignment + function + 10162 + 1 + 1388 + timetz + pg_catalog + 1184 + timestamptz + pg_catalog + 1266 + timetz + pg_catalog + + + assignment + function + 10160 + 1 + 2019 + time + pg_catalog + 1184 + timestamptz + pg_catalog + 1083 + time + pg_catalog + + + assignment + function + 10161 + 1 + 2027 + timestamp + pg_catalog + 1184 + timestamptz + pg_catalog + 1114 + timestamp + pg_catalog + + + implicit + function + 10208 + 1 + 1967 + timestamptz + pg_catalog + 1184 + timestamptz + pg_catalog + 1184 + timestamptz + pg_catalog + + + implicit + function + 10209 + 1 + 1200 + interval + pg_catalog + 1186 + interval + pg_catalog + 1186 + interval + pg_catalog + + + assignment + function + 10163 + 1 + 1419 + time + pg_catalog + 1186 + interval + pg_catalog + 1083 + time + pg_catalog + + + assignment + function + 10164 + 1 + 2046 + time + pg_catalog + 1266 + timetz + pg_catalog + 1083 + time + pg_catalog + + + implicit + function + 10210 + 1 + 1969 + timetz + pg_catalog + 1266 + timetz + pg_catalog + 1266 + timetz + pg_catalog + + + explicit + function + 10187 + 1 + 2076 + int8 + pg_catalog + 1560 + bit + pg_catalog + 20 + int8 + pg_catalog + + + implicit + function + 10211 + 1 + 1685 + bit + pg_catalog + 1560 + bit + pg_catalog + 1560 + bit + pg_catalog + + + implicit + binary + 10183 + 1 + 1560 + bit + pg_catalog + 1562 + varbit + pg_catalog + + + explicit + function + 10188 + 1 + 1684 + int4 + pg_catalog + 1560 + bit + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10184 + 1 + 1562 + varbit + pg_catalog + 1560 + bit + pg_catalog + + + implicit + function + 10212 + 1 + 1687 + varbit + pg_catalog + 1562 + varbit + pg_catalog + 1562 + varbit + pg_catalog + + + assignment + function + 10025 + 1 + 1779 + int8 + pg_catalog + 1700 + numeric + pg_catalog + 20 + int8 + pg_catalog + + + assignment + function + 10026 + 1 + 1783 + int2 + pg_catalog + 1700 + numeric + pg_catalog + 21 + int2 + pg_catalog + + + assignment + function + 10027 + 1 + 1744 + int4 + pg_catalog + 1700 + numeric + pg_catalog + 23 + int4 + pg_catalog + + + implicit + function + 10213 + 1 + 1703 + numeric + pg_catalog + 1700 + numeric + pg_catalog + 1700 + numeric + pg_catalog + + + implicit + function + 10029 + 1 + 1746 + float8 + pg_catalog + 1700 + numeric + pg_catalog + 701 + float8 + pg_catalog + + + assignment + function + 10031 + 1 + 3824 + money + pg_catalog + 1700 + numeric + pg_catalog + 790 + money + pg_catalog + + + implicit + function + 10028 + 1 + 1745 + float4 + pg_catalog + 1700 + numeric + pg_catalog + 700 + float4 + pg_catalog + + + assignment + binary + 10057 + 1 + 2202 + regprocedure + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10052 + 1 + 2202 + regprocedure + pg_catalog + 26 + oid + pg_catalog + + + assignment + function + 10056 + 1 + 1288 + int8 + pg_catalog + 2202 + regprocedure + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10050 + 1 + 2202 + regprocedure + pg_catalog + 24 + regproc + pg_catalog + + + implicit + binary + 10065 + 1 + 2203 + regoper + pg_catalog + 2204 + regoperator + pg_catalog + + + assignment + function + 10063 + 1 + 1288 + int8 + pg_catalog + 2203 + regoper + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10059 + 1 + 2203 + regoper + pg_catalog + 26 + oid + pg_catalog + + + assignment + binary + 10064 + 1 + 2203 + regoper + pg_catalog + 23 + int4 + pg_catalog + + + assignment + binary + 10073 + 1 + 2204 + regoperator + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10068 + 1 + 2204 + regoperator + pg_catalog + 26 + oid + pg_catalog + + + assignment + function + 10072 + 1 + 1288 + int8 + pg_catalog + 2204 + regoperator + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10066 + 1 + 2204 + regoperator + pg_catalog + 2203 + regoper + pg_catalog + + + assignment + function + 10079 + 1 + 1288 + int8 + pg_catalog + 2205 + regclass + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10075 + 1 + 2205 + regclass + pg_catalog + 26 + oid + pg_catalog + + + assignment + binary + 10080 + 1 + 2205 + regclass + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10093 + 1 + 1288 + int8 + pg_catalog + 2206 + regtype + pg_catalog + 20 + int8 + pg_catalog + + + assignment + binary + 10094 + 1 + 2206 + regtype + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10089 + 1 + 2206 + regtype + pg_catalog + 26 + oid + pg_catalog + + + implicit + binary + 10146 + 1 + 3361 + pg_ndistinct + pg_catalog + 17 + bytea + pg_catalog + + + implicit + io + 10147 + 1 + 3361 + pg_ndistinct + pg_catalog + 25 + text + pg_catalog + + + implicit + binary + 10148 + 1 + 3402 + pg_dependencies + pg_catalog + 17 + bytea + pg_catalog + + + implicit + io + 10149 + 1 + 3402 + pg_dependencies + pg_catalog + 25 + text + pg_catalog + + + implicit + binary + 10096 + 1 + 3734 + regconfig + pg_catalog + 26 + oid + pg_catalog + + + assignment + function + 10100 + 1 + 1288 + int8 + pg_catalog + 3734 + regconfig + pg_catalog + 20 + int8 + pg_catalog + + + assignment + binary + 10101 + 1 + 3734 + regconfig + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10103 + 1 + 3769 + regdictionary + pg_catalog + 26 + oid + pg_catalog + + + assignment + binary + 10108 + 1 + 3769 + regdictionary + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10107 + 1 + 1288 + int8 + pg_catalog + 3769 + regdictionary + pg_catalog + 20 + int8 + pg_catalog + + + assignment + io + 10215 + 1 + 3802 + jsonb + pg_catalog + 114 + json + pg_catalog + + + explicit + function + 10218 + 1 + 3450 + int2 + pg_catalog + 3802 + jsonb + pg_catalog + 21 + int2 + pg_catalog + + + explicit + function + 10220 + 1 + 3452 + int8 + pg_catalog + 3802 + jsonb + pg_catalog + 20 + int8 + pg_catalog + + + explicit + function + 10219 + 1 + 3451 + int4 + pg_catalog + 3802 + jsonb + pg_catalog + 23 + int4 + pg_catalog + + + explicit + function + 10216 + 1 + 3556 + bool + pg_catalog + 3802 + jsonb + pg_catalog + 16 + bool + pg_catalog + + + explicit + function + 10221 + 1 + 3453 + float4 + pg_catalog + 3802 + jsonb + pg_catalog + 700 + float4 + pg_catalog + + + explicit + function + 10217 + 1 + 3449 + numeric + pg_catalog + 3802 + jsonb + pg_catalog + 1700 + numeric + pg_catalog + + + explicit + function + 10222 + 1 + 2580 + float8 + pg_catalog + 3802 + jsonb + pg_catalog + 701 + float8 + pg_catalog + + + explicit + function + 10223 + 1 + 4281 + int4multirange + pg_catalog + 3904 + int4range + pg_catalog + 4451 + int4multirange + pg_catalog + + + explicit + function + 10225 + 1 + 4284 + nummultirange + pg_catalog + 3906 + numrange + pg_catalog + 4532 + nummultirange + pg_catalog + + + explicit + function + 10227 + 1 + 4287 + tsmultirange + pg_catalog + 3908 + tsrange + pg_catalog + 4533 + tsmultirange + pg_catalog + + + explicit + function + 10228 + 1 + 4290 + tstzmultirange + pg_catalog + 3910 + tstzrange + pg_catalog + 4534 + tstzmultirange + pg_catalog + + + explicit + function + 10226 + 1 + 4293 + datemultirange + pg_catalog + 3912 + daterange + pg_catalog + 4535 + datemultirange + pg_catalog + + + explicit + function + 10224 + 1 + 4296 + int8multirange + pg_catalog + 3926 + int8range + pg_catalog + 4536 + int8multirange + pg_catalog + + + assignment + binary + 10124 + 1 + 4089 + regnamespace + pg_catalog + 23 + int4 + pg_catalog + + + assignment + function + 10123 + 1 + 1288 + int8 + pg_catalog + 4089 + regnamespace + pg_catalog + 20 + int8 + pg_catalog + + + implicit + binary + 10119 + 1 + 4089 + regnamespace + pg_catalog + 26 + oid + pg_catalog + + + assignment + binary + 10117 + 1 + 4096 + regrole + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10112 + 1 + 4096 + regrole + pg_catalog + 26 + oid + pg_catalog + + + assignment + function + 10116 + 1 + 1288 + int8 + pg_catalog + 4096 + regrole + pg_catalog + 20 + int8 + pg_catalog + + + assignment + function + 10086 + 1 + 1288 + int8 + pg_catalog + 4191 + regcollation + pg_catalog + 20 + int8 + pg_catalog + + + assignment + binary + 10087 + 1 + 4191 + regcollation + pg_catalog + 23 + int4 + pg_catalog + + + implicit + binary + 10082 + 1 + 4191 + regcollation + pg_catalog + 26 + oid + pg_catalog + + + implicit + binary + 10150 + 1 + 5017 + pg_mcv_list + pg_catalog + 17 + bytea + pg_catalog + + + implicit + io + 10151 + 1 + 5017 + pg_mcv_list + pg_catalog + 25 + text + pg_catalog + + + explicit + function + 10036 + 1 + 5071 + xid + pg_catalog + 5069 + xid8 + pg_catalog + 28 + xid + pg_catalog + + + PL/pgSQL procedural language + 13826 + 683 + 1.0 + 11 + pg_catalog + 13827 +13828 +13829 +13830 + + + dynamically-loaded C functions + 13 + 1 + fmgr_c_validator + pg_catalog + + + built-in functions + 12 + 1 + fmgr_internal_validator + pg_catalog + + + PL/pgSQL procedural language + plpgsql_call_handler + pg_catalog + plpgsql_inline_handler + pg_catalog + 13830 + 683 + 1 + plpgsql_validator + pg_catalog + + + SQL-language functions + 14 + 1 + 1 + fmgr_sql_validator + pg_catalog + + + 13474 + 529 + littlesheep + + + system catalog schema + 11 + 523 + littlesheep + + + standard public schema + 1 + 6258 + 2024-04-20.06:09:48 + 2200 + 523 + pg_database_owner + + + bigint|0s + 37369 + 1 + 1 + 6233 + littlesheep + + + bigint|0s + 37385 + 1 + 1 + 6236 + littlesheep + + + bigint|0s + 37354 + 1 + 1 + 6231 + littlesheep + + + bigint|0s + 37339 + 1 + 1 + 6229 + littlesheep + + + bigint|0s + 37313 + 1 + 1 + 6224 + littlesheep + + + bigint|0s + 37474 + 1 + 1 + 6247 + littlesheep + + + bigint|0s + 37439 + 1 + 1 + 6243 + littlesheep + + + bigint|0s + 37324 + 1 + 1 + 6227 + littlesheep + + + bigint|0s + 37419 + 1 + 1 + 6241 + littlesheep + + + bigint|0s + 37459 + 1 + 1 + 6245 + littlesheep + + + bigint|0s + 37509 + 1 + 1 + 6251 + littlesheep + + + bigint|0s + 37489 + 1 + 1 + 6249 + littlesheep + + + bigint|0s + 37403 + 1 + 1 + 6238 + littlesheep + + + 37370 + 6233 + 2 + littlesheep +
+ + 37386 + 6236 + 2 + littlesheep +
+ + 37355 + 6231 + 2 + littlesheep +
+ + 37340 + 6229 + 2 + littlesheep +
+ + 37314 + 6227 + 2 + littlesheep +
+ + 37475 + 6247 + 2 + littlesheep +
+ + 37440 + 6243 + 2 + littlesheep +
+ + 37325 + 6227 + 2 + littlesheep +
+ + 37420 + 6241 + 2 + littlesheep +
+ + 37460 + 6245 + 2 + littlesheep +
+ + 37510 + 6251 + 2 + littlesheep +
+ + 37490 + 6249 + 2 + littlesheep +
+ + 37404 + 6238 + 2 + littlesheep +
+ + bigint|0s + nextval('passport_account_contacts_id_seq'::regclass) + 1 + 1 + 6233 + 37369 + 20 + + + timestamp with time zone|0s + 2 + 6233 + 1184 + + + timestamp with time zone|0s + 3 + 6233 + 1184 + + + timestamp with time zone|0s + 4 + 6233 + 1184 + + + smallint|0s + 5 + 6233 + 21 + + + text|0s + 6 + 6233 + 25 + + + boolean|0s + 7 + 6233 + 16 + + + boolean|0s + 8 + 6233 + 16 + + + timestamp with time zone|0s + 9 + 6233 + 1184 + + + bigint|0s + 10 + 6233 + 20 + + + account_id + 37378 + 6233 + 1 + 37314 + + + id + 1 + 37376 + 1 + 6233 + 1 + 403 + + + content + 37383 + 6234 + 1 + 403 + default + 100 + pg_catalog + + + deleted_at + 37384 + 6235 + 403 + + + 1 + 37377 + 1 + 6233 + 37376 + + + bigint|0s + nextval('passport_account_friendships_id_seq'::regclass) + 1 + 1 + 6236 + 37385 + 20 + + + timestamp with time zone|0s + 2 + 6236 + 1184 + + + timestamp with time zone|0s + 3 + 6236 + 1184 + + + timestamp with time zone|0s + 4 + 6236 + 1184 + + + bigint|0s + 5 + 6236 + 20 + + + bigint|0s + 6 + 6236 + 20 + + + bigint|0s + 7 + 6236 + 20 + + + smallint|0s + 8 + 6236 + 21 + + + account_id + 37392 + 6236 + 1 + 37314 + + + related_id + 37397 + 6236 + 1 + 37314 + + + id + 1 + 37390 + 1 + 6236 + 1 + 403 + + + deleted_at + 37402 + 6237 + 403 + + + 1 + 37391 + 1 + 6236 + 37390 + + + bigint|0s + nextval('passport_account_pages_id_seq'::regclass) + 1 + 1 + 6231 + 37354 + 20 + + + timestamp with time zone|0s + 2 + 6231 + 1184 + + + timestamp with time zone|0s + 3 + 6231 + 1184 + + + timestamp with time zone|0s + 4 + 6231 + 1184 + + + text|0s + 5 + 6231 + 25 + + + text|0s + 6 + 6231 + 25 + + + text|0s + 7 + 6231 + 25 + + + jsonb|0s + 8 + 6231 + 3802 + + + bigint|0s + 9 + 6231 + 20 + + + account_id + 37363 + 6231 + 1 + 37314 + + + id + 1 + 37361 + 1 + 6231 + 1 + 403 + + + deleted_at + 37368 + 6232 + 403 + + + 1 + 37362 + 1 + 6231 + 37361 + + + bigint|0s + nextval('passport_account_profiles_id_seq'::regclass) + 1 + 1 + 6229 + 37339 + 20 + + + timestamp with time zone|0s + 2 + 6229 + 1184 + + + timestamp with time zone|0s + 3 + 6229 + 1184 + + + timestamp with time zone|0s + 4 + 6229 + 1184 + + + text|0s + 5 + 6229 + 25 + + + text|0s + 6 + 6229 + 25 + + + bigint|0s + 7 + 6229 + 20 + + + timestamp with time zone|0s + 8 + 6229 + 1184 + + + bigint|0s + 9 + 6229 + 20 + + + account_id + 37348 + 6229 + 1 + 37314 + + + id + 1 + 37346 + 1 + 6229 + 1 + 403 + + + deleted_at + 37353 + 6230 + 403 + + + 1 + 37347 + 1 + 6229 + 37346 + + + bigint|0s + nextval('passport_accounts_id_seq'::regclass) + 1 + 1 + 6224 + 37313 + 20 + + + timestamp with time zone|0s + 2 + 6224 + 1184 + + + timestamp with time zone|0s + 3 + 6224 + 1184 + + + timestamp with time zone|0s + 4 + 6224 + 1184 + + + text|0s + 5 + 6224 + 25 + + + text|0s + 6 + 6224 + 25 + + + text|0s + 7 + 6224 + 25 + + + text|0s + 8 + 6224 + 25 + + + text|0s + 9 + 6224 + 25 + + + timestamp with time zone|0s + 10 + 6224 + 1184 + + + bigint|0s + 11 + 6224 + 20 + + + id + 1 + 37320 + 1 + 6224 + 1 + 403 + + + name + 37322 + 6225 + 1 + 403 + default + 100 + pg_catalog + + + deleted_at + 37323 + 6226 + 403 + + + 1 + 37321 + 1 + 6224 + 37320 + + + bigint|0s + nextval('passport_action_events_id_seq'::regclass) + 1 + 1 + 6247 + 37474 + 20 + + + timestamp with time zone|0s + 2 + 6247 + 1184 + + + timestamp with time zone|0s + 3 + 6247 + 1184 + + + timestamp with time zone|0s + 4 + 6247 + 1184 + + + text|0s + 5 + 6247 + 25 + + + text|0s + 6 + 6247 + 25 + + + text|0s + 7 + 6247 + 25 + + + text|0s + 8 + 6247 + 25 + + + text|0s + 9 + 6247 + 25 + + + bigint|0s + 10 + 6247 + 20 + + + account_id + 37483 + 6247 + 1 + 37314 + + + id + 1 + 37481 + 1 + 6247 + 1 + 403 + + + deleted_at + 37488 + 6248 + 403 + + + 1 + 37482 + 1 + 6247 + 37481 + + + bigint|0s + nextval('passport_auth_challenges_id_seq'::regclass) + 1 + 1 + 6243 + 37439 + 20 + + + timestamp with time zone|0s + 2 + 6243 + 1184 + + + timestamp with time zone|0s + 3 + 6243 + 1184 + + + timestamp with time zone|0s + 4 + 6243 + 1184 + + + text|0s + 5 + 6243 + 25 + + + text|0s + 6 + 6243 + 25 + + + text|0s + 7 + 6243 + 25 + + + bigint|0s + 8 + 6243 + 20 + + + bigint|0s + 9 + 6243 + 20 + + + bigint|0s + 10 + 6243 + 20 + + + jsonb|0s + 11 + 6243 + 3802 + + + smallint|0s + 12 + 6243 + 21 + + + timestamp with time zone|0s + 13 + 6243 + 1184 + + + bigint|0s + 14 + 6243 + 20 + + + bigint|0s + 15 + 6243 + 20 + + + session_id + 37448 + 6243 + 1 + 37420 + + + account_id + 37453 + 6243 + 1 + 37314 + + + id + 1 + 37446 + 1 + 6243 + 1 + 403 + + + deleted_at + 37458 + 6244 + 403 + + + 1 + 37447 + 1 + 6243 + 37446 + + + bigint|0s + nextval('passport_auth_factors_id_seq'::regclass) + 1 + 1 + 6227 + 37324 + 20 + + + timestamp with time zone|0s + 2 + 6227 + 1184 + + + timestamp with time zone|0s + 3 + 6227 + 1184 + + + timestamp with time zone|0s + 4 + 6227 + 1184 + + + smallint|0s + 5 + 6227 + 21 + + + text|0s + 6 + 6227 + 25 + + + jsonb|0s + 7 + 6227 + 3802 + + + bigint|0s + 8 + 6227 + 20 + + + account_id + 37333 + 6227 + 1 + 37314 + + + id + 1 + 37331 + 1 + 6227 + 1 + 403 + + + deleted_at + 37338 + 6228 + 403 + + + 1 + 37332 + 1 + 6227 + 37331 + + + bigint|0s + nextval('passport_auth_sessions_id_seq'::regclass) + 1 + 1 + 6241 + 37419 + 20 + + + timestamp with time zone|0s + 2 + 6241 + 1184 + + + timestamp with time zone|0s + 3 + 6241 + 1184 + + + timestamp with time zone|0s + 4 + 6241 + 1184 + + + jsonb|0s + 5 + 6241 + 3802 + + + jsonb|0s + 6 + 6241 + 3802 + + + text|0s + 7 + 6241 + 25 + + + text|0s + 8 + 6241 + 25 + + + text|0s + 9 + 6241 + 25 + + + timestamp with time zone|0s + 10 + 6241 + 1184 + + + timestamp with time zone|0s + 11 + 6241 + 1184 + + + timestamp with time zone|0s + 12 + 6241 + 1184 + + + bigint|0s + 13 + 6241 + 20 + + + bigint|0s + 14 + 6241 + 20 + + + client_id + 37428 + 6241 + 1 + 37404 + + + account_id + 37433 + 6241 + 1 + 37314 + + + id + 1 + 37426 + 1 + 6241 + 1 + 403 + + + deleted_at + 37438 + 6242 + 403 + + + 1 + 37427 + 1 + 6241 + 37426 + + + bigint|0s + nextval('passport_magic_tokens_id_seq'::regclass) + 1 + 1 + 6245 + 37459 + 20 + + + timestamp with time zone|0s + 2 + 6245 + 1184 + + + timestamp with time zone|0s + 3 + 6245 + 1184 + + + timestamp with time zone|0s + 4 + 6245 + 1184 + + + text|0s + 5 + 6245 + 25 + + + smallint|0s + 6 + 6245 + 21 + + + bigint|0s + 7 + 6245 + 20 + + + timestamp with time zone|0s + 8 + 6245 + 1184 + + + assign_to + 37468 + 6245 + 1 + 37314 + + + id + 1 + 37466 + 1 + 6245 + 1 + 403 + + + deleted_at + 37473 + 6246 + 403 + + + 1 + 37467 + 1 + 6245 + 37466 + + + bigint|0s + nextval('passport_notification_subscribers_id_seq'::regclass) + 1 + 1 + 6251 + 37509 + 20 + + + timestamp with time zone|0s + 2 + 6251 + 1184 + + + timestamp with time zone|0s + 3 + 6251 + 1184 + + + timestamp with time zone|0s + 4 + 6251 + 1184 + + + text|0s + 5 + 6251 + 25 + + + text|0s + 6 + 6251 + 25 + + + text|0s + 7 + 6251 + 25 + + + bigint|0s + 8 + 6251 + 20 + + + account_id + 37518 + 6251 + 1 + 37314 + + + id + 1 + 37516 + 1 + 6251 + 1 + 403 + + + device_id + 37523 + 6252 + 1 + 403 + default + 100 + pg_catalog + + + deleted_at + 37524 + 6253 + 403 + + + 1 + 37517 + 1 + 6251 + 37516 + + + bigint|0s + nextval('passport_notifications_id_seq'::regclass) + 1 + 1 + 6249 + 37489 + 20 + + + timestamp with time zone|0s + 2 + 6249 + 1184 + + + timestamp with time zone|0s + 3 + 6249 + 1184 + + + timestamp with time zone|0s + 4 + 6249 + 1184 + + + text|0s + 5 + 6249 + 25 + + + text|0s + 6 + 6249 + 25 + + + jsonb|0s + 7 + 6249 + 3802 + + + boolean|0s + 8 + 6249 + 16 + + + timestamp with time zone|0s + 9 + 6249 + 1184 + + + bigint|0s + 10 + 6249 + 20 + + + bigint|0s + 11 + 6249 + 20 + + + sender_id + 37498 + 6249 + 1 + 37404 + + + recipient_id + 37503 + 6249 + 1 + 37314 + + + id + 1 + 37496 + 1 + 6249 + 1 + 403 + + + deleted_at + 37508 + 6250 + 403 + + + 1 + 37497 + 1 + 6249 + 37496 + + + bigint|0s + nextval('passport_third_clients_id_seq'::regclass) + 1 + 1 + 6238 + 37403 + 20 + + + timestamp with time zone|0s + 2 + 6238 + 1184 + + + timestamp with time zone|0s + 3 + 6238 + 1184 + + + timestamp with time zone|0s + 4 + 6238 + 1184 + + + text|0s + 5 + 6238 + 25 + + + text|0s + 6 + 6238 + 25 + + + text|0s + 7 + 6238 + 25 + + + text|0s + 8 + 6238 + 25 + + + jsonb|0s + 9 + 6238 + 3802 + + + jsonb|0s + 10 + 6238 + 3802 + + + boolean|0s + 11 + 6238 + 16 + + + bigint|0s + 12 + 6238 + 20 + + + account_id + 37412 + 6238 + 1 + 37314 + + + id + 1 + 37410 + 1 + 6238 + 1 + 403 + + + alias + 37417 + 6239 + 1 + 403 + default + 100 + pg_catalog + + + deleted_at + 37418 + 6240 + 403 + + + 1 + 37411 + 1 + 6238 + 37410 + +
+
\ No newline at end of file diff --git a/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ.meta b/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ.meta new file mode 100644 index 0000000..951b9f0 --- /dev/null +++ b/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ.meta @@ -0,0 +1 @@ +#n:hy_passport \ No newline at end of file diff --git a/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ/schema/public.abK9xQ.meta b/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ/schema/public.abK9xQ.meta new file mode 100644 index 0000000..a9e0cff --- /dev/null +++ b/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ/schema/public.abK9xQ.meta @@ -0,0 +1,2 @@ +#n:public +! [6258, 0, null, null, -2147483648, -2147483648] diff --git a/.idea/workspace.xml b/.idea/workspace.xml index c7f72d7..4695490 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,73 +4,12 @@ + + + + true diff --git a/pkg/database/migrator.go b/pkg/database/migrator.go index 3631ec7..195d50f 100644 --- a/pkg/database/migrator.go +++ b/pkg/database/migrator.go @@ -12,8 +12,7 @@ var DatabaseAutoActionRange = []any{ &models.AccountPage{}, &models.AccountContact{}, &models.AccountFriendship{}, - &models.AuthSession{}, - &models.AuthChallenge{}, + &models.AuthTicket{}, &models.MagicToken{}, &models.ThirdClient{}, &models.ActionEvent{}, diff --git a/pkg/models/accounts.go b/pkg/models/accounts.go index 6d43937..ab8c96a 100644 --- a/pkg/models/accounts.go +++ b/pkg/models/accounts.go @@ -23,9 +23,8 @@ type Account struct { PersonalPage AccountPage `json:"personal_page"` Contacts []AccountContact `json:"contacts"` - Sessions []AuthSession `json:"sessions"` - Challenges []AuthChallenge `json:"challenges"` - Factors []AuthFactor `json:"factors"` + Sessions []AuthTicket `json:"sessions"` + Factors []AuthFactor `json:"factors"` Events []ActionEvent `json:"events"` MagicTokens []MagicToken `json:"-" gorm:"foreignKey:AssignTo"` diff --git a/pkg/models/auth.go b/pkg/models/auth.go index e74d5a3..913789f 100644 --- a/pkg/models/auth.go +++ b/pkg/models/auth.go @@ -23,23 +23,30 @@ type AuthFactor struct { AccountID uint `json:"account_id"` } -type AuthSession struct { +type AuthTicket struct { BaseModel - Claims datatypes.JSONSlice[string] `json:"claims"` - Audiences datatypes.JSONSlice[string] `json:"audiences"` - Challenge AuthChallenge `json:"challenge" gorm:"foreignKey:SessionID"` - GrantToken string `json:"grant_token"` - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - ExpiredAt *time.Time `json:"expired_at"` - AvailableAt *time.Time `json:"available_at"` - LastGrantAt *time.Time `json:"last_grant_at"` - ClientID *uint `json:"client_id"` - AccountID uint `json:"account_id"` + Location string `json:"location"` + IpAddress string `json:"ip_address"` + UserAgent string `json:"user_agent"` + RequireMFA bool `json:"require_mfa"` + RequireAuthenticate bool `json:"require_authenticate"` + Claims datatypes.JSONSlice[string] `json:"claims"` + Audiences datatypes.JSONSlice[string] `json:"audiences"` + GrantToken *string `json:"grant_token"` + AccessToken *string `json:"access_token"` + RefreshToken *string `json:"refresh_token"` + ExpiredAt *time.Time `json:"expired_at"` + AvailableAt *time.Time `json:"available_at"` + LastGrantAt *time.Time `json:"last_grant_at"` + ClientID *uint `json:"client_id"` + AccountID uint `json:"account_id"` } -func (v AuthSession) IsAvailable() error { +func (v AuthTicket) IsAvailable() error { + if v.RequireMFA || v.RequireAuthenticate { + return fmt.Errorf("session isn't authenticated yet") + } if v.AvailableAt != nil && time.Now().Unix() < v.AvailableAt.Unix() { return fmt.Errorf("session isn't available yet") } @@ -50,40 +57,8 @@ func (v AuthSession) IsAvailable() error { return nil } -type AuthChallengeState = int8 - -const ( - ActiveChallengeState = AuthChallengeState(iota) - ExpiredChallengeState - FinishChallengeState -) - -type AuthChallenge struct { - BaseModel - - Location string `json:"location"` - IpAddress string `json:"ip_address"` - UserAgent string `json:"user_agent"` - RiskLevel int `json:"risk_level"` - Progress int `json:"progress"` - Requirements int `json:"requirements"` - BlacklistFactors datatypes.JSONType[[]uint] `json:"blacklist_factors"` - State int8 `json:"state"` - ExpiredAt time.Time `json:"expired_at"` - SessionID *uint `json:"session_id"` - AccountID uint `json:"account_id"` -} - -func (v AuthChallenge) IsAvailable() error { - if time.Now().Unix() > v.ExpiredAt.Unix() { - return fmt.Errorf("challenge expired") - } - - return nil -} - type AuthContext struct { - Session AuthSession `json:"session"` - Account Account `json:"account"` - ExpiredAt time.Time `json:"expired_at"` + Ticket AuthTicket `json:"session"` + Account Account `json:"account"` + ExpiredAt time.Time `json:"expired_at"` } diff --git a/pkg/models/clients.go b/pkg/models/clients.go index 5eafc53..01ae4ee 100644 --- a/pkg/models/clients.go +++ b/pkg/models/clients.go @@ -11,7 +11,7 @@ type ThirdClient struct { Secret string `json:"secret"` Urls datatypes.JSONSlice[string] `json:"urls"` Callbacks datatypes.JSONSlice[string] `json:"callbacks"` - Sessions []AuthSession `json:"sessions" gorm:"foreignKey:ClientID"` + Sessions []AuthTicket `json:"sessions" gorm:"foreignKey:ClientID"` Notifications []Notification `json:"notifications" gorm:"foreignKey:SenderID"` IsDraft bool `json:"is_draft"` AccountID *uint `json:"account_id"` diff --git a/pkg/security/challanges.go b/pkg/security/challanges.go deleted file mode 100644 index 0db0200..0000000 --- a/pkg/security/challanges.go +++ /dev/null @@ -1,96 +0,0 @@ -package security - -import ( - "fmt" - "strings" - "time" - - "github.com/google/uuid" - - "git.solsynth.dev/hydrogen/passport/pkg/database" - "git.solsynth.dev/hydrogen/passport/pkg/models" - "github.com/samber/lo" - "gorm.io/datatypes" -) - -func CalcRisk(user models.Account, ip, ua string) int { - risk := 3 - var secureFactor int64 - if err := database.C.Where(models.AuthChallenge{ - AccountID: user.ID, - IpAddress: ip, - }).Model(models.AuthChallenge{}).Count(&secureFactor).Error; err == nil { - if secureFactor >= 3 { - risk -= 3 - } else if secureFactor >= 1 { - risk -= 2 - } - } - - return risk -} - -func NewChallenge(user models.Account, factors []models.AuthFactor, ip, ua string) (models.AuthChallenge, error) { - var challenge models.AuthChallenge - // Pickup any challenge if possible - if err := database.C.Where(models.AuthChallenge{ - AccountID: user.ID, - }).Where("state = ?", models.ActiveChallengeState).First(&challenge).Error; err == nil { - return challenge, nil - } - - // Calculate the risk level - risk := CalcRisk(user, ip, ua) - - // Clamp risk in the exists requirements factor count - requirements := lo.Clamp(risk, 1, len(factors)) - - challenge = models.AuthChallenge{ - IpAddress: ip, - UserAgent: ua, - RiskLevel: risk, - Requirements: requirements, - BlacklistFactors: datatypes.NewJSONType([]uint{}), - State: models.ActiveChallengeState, - ExpiredAt: time.Now().Add(2 * time.Hour), - AccountID: user.ID, - } - - err := database.C.Save(&challenge).Error - - return challenge, err -} - -func DoChallenge(challenge models.AuthChallenge, factor models.AuthFactor, code string) error { - if err := challenge.IsAvailable(); err != nil { - challenge.State = models.ExpiredChallengeState - database.C.Save(&challenge) - return err - } - if challenge.Progress >= challenge.Requirements { - return fmt.Errorf("challenge already passed") - } - - blacklist := challenge.BlacklistFactors.Data() - if lo.Contains(blacklist, factor.ID) { - return fmt.Errorf("factor in blacklist, please change another factor to challenge") - } - if err := VerifyFactor(factor, code); err != nil { - return err - } - - challenge.Progress++ - challenge.BlacklistFactors = datatypes.NewJSONType(append(blacklist, factor.ID)) - - if err := database.C.Save(&challenge).Error; err != nil { - return err - } - - // Revoke some factor passwords - if factor.Type == models.EmailPasswordFactor { - factor.Secret = strings.ReplaceAll(uuid.NewString(), "-", "") - database.C.Save(&factor) - } - - return nil -} diff --git a/pkg/security/factors.go b/pkg/security/factors.go deleted file mode 100644 index 5d86876..0000000 --- a/pkg/security/factors.go +++ /dev/null @@ -1,27 +0,0 @@ -package security - -import ( - "fmt" - - "git.solsynth.dev/hydrogen/passport/pkg/models" - "github.com/samber/lo" -) - -func VerifyFactor(factor models.AuthFactor, code string) error { - switch factor.Type { - case models.PasswordAuthFactor: - return lo.Ternary( - VerifyPassword(code, factor.Secret), - nil, - fmt.Errorf("invalid password"), - ) - case models.EmailPasswordFactor: - return lo.Ternary( - code == factor.Secret, - nil, - fmt.Errorf("invalid verification code"), - ) - } - - return nil -} diff --git a/pkg/security/sessions.go b/pkg/security/sessions.go deleted file mode 100644 index abfc4fe..0000000 --- a/pkg/security/sessions.go +++ /dev/null @@ -1,165 +0,0 @@ -package security - -import ( - "fmt" - "strconv" - "time" - - "github.com/spf13/viper" - - "git.solsynth.dev/hydrogen/passport/pkg/database" - "git.solsynth.dev/hydrogen/passport/pkg/models" - "github.com/google/uuid" - "github.com/samber/lo" -) - -func GrantSession(challenge models.AuthChallenge, claims, audiences []string, expired, available *time.Time) (models.AuthSession, error) { - var session models.AuthSession - if err := challenge.IsAvailable(); err != nil { - return session, err - } - if challenge.Progress < challenge.Requirements { - return session, fmt.Errorf("challenge haven't passed") - } - - challenge.State = models.FinishChallengeState - - session = models.AuthSession{ - Claims: claims, - Audiences: audiences, - Challenge: challenge, - GrantToken: uuid.NewString(), - AccessToken: uuid.NewString(), - RefreshToken: uuid.NewString(), - ExpiredAt: expired, - AvailableAt: available, - AccountID: challenge.AccountID, - } - - if err := database.C.Save(&challenge).Error; err != nil { - return session, err - } else if err := database.C.Save(&session).Error; err != nil { - return session, err - } - - return session, nil -} - -func GrantOauthSession(user models.Account, client models.ThirdClient, claims, audiences []string, expired, available *time.Time, ip, ua string) (models.AuthSession, error) { - session := models.AuthSession{ - Claims: claims, - Audiences: audiences, - Challenge: models.AuthChallenge{ - IpAddress: ip, - UserAgent: ua, - RiskLevel: CalcRisk(user, ip, ua), - State: models.FinishChallengeState, - AccountID: user.ID, - }, - GrantToken: uuid.NewString(), - AccessToken: uuid.NewString(), - RefreshToken: uuid.NewString(), - ExpiredAt: expired, - AvailableAt: available, - ClientID: &client.ID, - AccountID: user.ID, - } - - if err := database.C.Save(&session).Error; err != nil { - return session, err - } - - return session, nil -} - -func RegenSession(session models.AuthSession) (models.AuthSession, error) { - session.GrantToken = uuid.NewString() - session.AccessToken = uuid.NewString() - session.RefreshToken = uuid.NewString() - err := database.C.Save(&session).Error - return session, err -} - -func GetToken(session models.AuthSession) (string, string, error) { - var refresh, access string - if err := session.IsAvailable(); err != nil { - return refresh, access, err - } - - accessDuration := time.Duration(viper.GetInt64("security.access_token_duration")) * time.Second - refreshDuration := time.Duration(viper.GetInt64("security.refresh_token_duration")) * time.Second - - var err error - sub := strconv.Itoa(int(session.AccountID)) - sed := strconv.Itoa(int(session.ID)) - access, err = EncodeJwt(session.AccessToken, JwtAccessType, sub, sed, session.Audiences, time.Now().Add(accessDuration)) - if err != nil { - return refresh, access, err - } - refresh, err = EncodeJwt(session.RefreshToken, JwtRefreshType, sub, sed, session.Audiences, time.Now().Add(refreshDuration)) - if err != nil { - return refresh, access, err - } - - session.LastGrantAt = lo.ToPtr(time.Now()) - database.C.Save(&session) - - return access, refresh, nil -} - -func ExchangeToken(token string) (string, string, error) { - var session models.AuthSession - if err := database.C.Where(models.AuthSession{GrantToken: token}).First(&session).Error; err != nil { - return "404", "403", err - } else if session.LastGrantAt != nil { - return "404", "403", fmt.Errorf("session was granted the first token, use refresh token instead") - } else if len(session.Audiences) > 1 { - return "404", "403", fmt.Errorf("should use authorization code grant type") - } - - return GetToken(session) -} - -func ExchangeOauthToken(clientId, clientSecret, redirectUri, token string) (string, string, error) { - var client models.ThirdClient - if err := database.C.Where(models.ThirdClient{Alias: clientId}).First(&client).Error; err != nil { - return "404", "403", err - } else if client.Secret != clientSecret { - return "404", "403", fmt.Errorf("invalid client secret") - } else if !client.IsDraft && !lo.Contains(client.Callbacks, redirectUri) { - return "404", "403", fmt.Errorf("invalid redirect uri") - } - - var session models.AuthSession - if err := database.C.Where(models.AuthSession{GrantToken: token}).First(&session).Error; err != nil { - return "404", "403", err - } else if session.LastGrantAt != nil { - return "404", "403", fmt.Errorf("session was granted the first token, use refresh token instead") - } - - return GetToken(session) -} - -func RefreshToken(token string) (string, string, error) { - parseInt := func(str string) int { - val, _ := strconv.Atoi(str) - return val - } - - var session models.AuthSession - if claims, err := DecodeJwt(token); err != nil { - return "404", "403", err - } else if claims.Type != JwtRefreshType { - return "404", "403", fmt.Errorf("invalid token type, expected refresh token") - } else if err := database.C.Where(models.AuthSession{ - BaseModel: models.BaseModel{ID: uint(parseInt(claims.SessionID))}, - }).First(&session).Error; err != nil { - return "404", "403", err - } - - if session, err := RegenSession(session); err != nil { - return "404", "403", err - } else { - return GetToken(session) - } -} diff --git a/pkg/server/accounts_api.go b/pkg/server/accounts_api.go index 96858fa..47683cf 100644 --- a/pkg/server/accounts_api.go +++ b/pkg/server/accounts_api.go @@ -114,7 +114,7 @@ func killSession(c *fiber.Ctx) error { user := c.Locals("principal").(models.Account) id, _ := c.ParamsInt("sessionId", 0) - if err := database.C.Delete(&models.AuthSession{}, &models.AuthSession{ + if err := database.C.Delete(&models.AuthTicket{}, &models.AuthTicket{ BaseModel: models.BaseModel{ID: uint(id)}, AccountID: user.ID, }).Error; err != nil { diff --git a/pkg/server/auth_api.go b/pkg/server/auth_api.go new file mode 100644 index 0000000..596242f --- /dev/null +++ b/pkg/server/auth_api.go @@ -0,0 +1,145 @@ +package server + +import ( + "fmt" + "time" + + "github.com/gofiber/fiber/v2" + + "git.solsynth.dev/hydrogen/passport/pkg/services" +) + +func doAuthenticate(c *fiber.Ctx) error { + var data struct { + Username string `json:"username"` + Password string `json:"password" validate:"required"` + } + + if err := BindAndValidate(c, &data); err != nil { + return err + } + + user, err := services.LookupAccount(data.Username) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("account was not found: %v", err.Error())) + } + + ticket, err := services.NewTicket(user, c.IP(), c.Get(fiber.HeaderUserAgent)) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable setup ticket: %v", err.Error())) + } + + ticket, err = services.ActiveTicketWithPassword(ticket, data.Password) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid password: %v", err.Error())) + } + + return c.JSON(fiber.Map{ + "is_finished": ticket.IsAvailable(), + "ticket": ticket, + }) +} + +func doMultiFactorAuthenticate(c *fiber.Ctx) error { + var data struct { + TicketID uint `json:"ticket_id" validate:"required"` + FactorID uint `json:"factor_id" validate:"required"` + Code string `json:"code" validate:"required"` + } + + if err := BindAndValidate(c, &data); err != nil { + return err + } + + ticket, err := services.GetTicket(data.TicketID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("ticket was not found: %v", err.Error())) + } + + factor, err := services.GetFactor(data.FactorID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("factor was not found: %v", err.Error())) + } + + ticket, err = services.ActiveTicketWithMFA(ticket, factor, data.Code) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid code: %v", err.Error())) + } + + return c.JSON(fiber.Map{ + "is_finished": ticket.IsAvailable(), + "ticket": ticket, + }) +} + +func getToken(c *fiber.Ctx) error { + var data struct { + Code string `json:"code" form:"code"` + RefreshToken string `json:"refresh_token" form:"refresh_token"` + ClientID string `json:"client_id" form:"client_id"` + ClientSecret string `json:"client_secret" form:"client_secret"` + Username string `json:"username" form:"username"` + Password string `json:"password" form:"password"` + RedirectUri string `json:"redirect_uri" form:"redirect_uri"` + GrantType string `json:"grant_type" form:"grant_type"` + } + + if err := BindAndValidate(c, &data); err != nil { + return err + } + + var err error + var access, refresh string + switch data.GrantType { + case "refresh_token": + // Refresh Token + access, refresh, err = services.RefreshToken(data.RefreshToken) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + case "authorization_code": + // Authorization Code Mode + access, refresh, err = services.ExchangeOauthToken(data.ClientID, data.ClientSecret, data.RedirectUri, data.Code) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + case "password": + // Password Mode + user, err := services.LookupAccount(data.Username) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("account was not found: %v", err.Error())) + } + ticket, err := services.NewTicket(user, c.IP(), c.Get(fiber.HeaderUserAgent)) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable setup ticket: %v", err.Error())) + } + ticket, err = services.ActiveTicketWithPassword(ticket, data.Password) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid password: %v", err.Error())) + } else if ticket.GrantToken == nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get grant token to get token")) + } + access, refresh, err = services.ExchangeOauthToken(data.ClientID, data.ClientSecret, data.RedirectUri, *ticket.GrantToken) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + case "grant_token": + // Internal Usage + access, refresh, err = services.ExchangeToken(data.Code) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + default: + return fiber.NewError(fiber.StatusBadRequest, "unsupported exchange token type") + } + + services.SetJwtCookieSet(c, access, refresh) + + return c.JSON(fiber.Map{ + "id_token": access, + "access_token": access, + "refresh_token": refresh, + "token_type": "Bearer", + "expires_in": (30 * time.Minute).Seconds(), + }) +} diff --git a/pkg/server/auth_middleware.go b/pkg/server/auth_middleware.go index 284c2ce..adb133b 100644 --- a/pkg/server/auth_middleware.go +++ b/pkg/server/auth_middleware.go @@ -3,14 +3,13 @@ package server import ( "strings" - "git.solsynth.dev/hydrogen/passport/pkg/security" "git.solsynth.dev/hydrogen/passport/pkg/services" "github.com/gofiber/fiber/v2" ) func authMiddleware(c *fiber.Ctx) error { var token string - if cookie := c.Cookies(security.CookieAccessKey); len(cookie) > 0 { + if cookie := c.Cookies(services.CookieAccessKey); len(cookie) > 0 { token = cookie } if header := c.Get(fiber.HeaderAuthorization); len(header) > 0 { @@ -42,10 +41,10 @@ func authFunc(c *fiber.Ctx, overrides ...string) error { } } - rtk := c.Cookies(security.CookieRefreshKey) + rtk := c.Cookies(services.CookieRefreshKey) if user, atk, rtk, err := services.Authenticate(token, rtk, 0); err == nil { if atk != token { - security.SetJwtCookieSet(c, atk, rtk) + services.SetJwtCookieSet(c, atk, rtk) } c.Locals("principal", user) return nil diff --git a/pkg/server/challanges_api.go b/pkg/server/challanges_api.go deleted file mode 100644 index 826724e..0000000 --- a/pkg/server/challanges_api.go +++ /dev/null @@ -1,140 +0,0 @@ -package server - -import ( - "time" - - "github.com/gofiber/fiber/v2" - - "git.solsynth.dev/hydrogen/passport/pkg/security" - "git.solsynth.dev/hydrogen/passport/pkg/services" - "github.com/samber/lo" -) - -func startChallenge(c *fiber.Ctx) error { - var data struct { - ID string `json:"id" validate:"required"` - } - - if err := BindAndValidate(c, &data); err != nil { - return err - } - - user, err := services.LookupAccount(data.ID) - if err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - factors, err := services.LookupFactorsByUser(user.ID) - if err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - - challenge, err := security.NewChallenge(user, factors, c.IP(), c.Get(fiber.HeaderUserAgent)) - if err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - - services.AddEvent(user, "challenges.start", data.ID, c.IP(), c.Get(fiber.HeaderUserAgent)) - return c.JSON(fiber.Map{ - "display_name": user.Nick, - "challenge": challenge, - "factors": factors, - }) -} - -func doChallenge(c *fiber.Ctx) error { - var data struct { - ChallengeID uint `json:"challenge_id" validate:"required"` - FactorID uint `json:"factor_id" validate:"required"` - Secret string `json:"secret" validate:"required"` - } - - if err := BindAndValidate(c, &data); err != nil { - return err - } - - challenge, err := services.LookupChallengeWithFingerprint(data.ChallengeID, c.IP(), c.Get(fiber.HeaderUserAgent)) - if err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - - factor, err := services.LookupFactor(data.FactorID) - if err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - - if err := security.DoChallenge(challenge, factor, data.Secret); err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - challenge, err = services.LookupChallenge(data.ChallengeID) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } else if challenge.Progress >= challenge.Requirements { - session, err := security.GrantSession(challenge, []string{"*"}, []string{"passport"}, nil, lo.ToPtr(time.Now())) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - return c.JSON(fiber.Map{ - "is_finished": true, - "challenge": challenge, - "session": session, - }) - } - - return c.JSON(fiber.Map{ - "is_finished": false, - "challenge": challenge, - "session": nil, - }) -} - -func exchangeToken(c *fiber.Ctx) error { - var data struct { - Code string `json:"code" form:"code"` - RefreshToken string `json:"refresh_token" form:"refresh_token"` - ClientID string `json:"client_id" form:"client_id"` - ClientSecret string `json:"client_secret" form:"client_secret"` - RedirectUri string `json:"redirect_uri" form:"redirect_uri"` - GrantType string `json:"grant_type" form:"grant_type"` - } - - if err := BindAndValidate(c, &data); err != nil { - return err - } - - var err error - var access, refresh string - switch data.GrantType { - case "authorization_code": - // Authorization Code Mode - access, refresh, err = security.ExchangeOauthToken(data.ClientID, data.ClientSecret, data.RedirectUri, data.Code) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - case "grant_token": - // Internal Usage - access, refresh, err = security.ExchangeToken(data.Code) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - case "refresh_token": - // Refresh Token - access, refresh, err = security.RefreshToken(data.RefreshToken) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - default: - return fiber.NewError(fiber.StatusBadRequest, "unsupported exchange token type") - } - - security.SetJwtCookieSet(c, access, refresh) - - return c.JSON(fiber.Map{ - "id_token": access, - "access_token": access, - "refresh_token": refresh, - "token_type": "Bearer", - "expires_in": (30 * time.Minute).Seconds(), - }) -} diff --git a/pkg/server/factors_api.go b/pkg/server/factors_api.go index 301547a..ae655bf 100644 --- a/pkg/server/factors_api.go +++ b/pkg/server/factors_api.go @@ -8,7 +8,7 @@ import ( func requestFactorToken(c *fiber.Ctx) error { id, _ := c.ParamsInt("factorId", 0) - factor, err := services.LookupFactor(uint(id)) + factor, err := services.GetFactor(uint(id)) if err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) } diff --git a/pkg/server/oauth_api.go b/pkg/server/oauth_api.go index c30c578..db7c653 100644 --- a/pkg/server/oauth_api.go +++ b/pkg/server/oauth_api.go @@ -6,7 +6,6 @@ import ( "git.solsynth.dev/hydrogen/passport/pkg/database" "git.solsynth.dev/hydrogen/passport/pkg/models" - "git.solsynth.dev/hydrogen/passport/pkg/security" "git.solsynth.dev/hydrogen/passport/pkg/services" "github.com/gofiber/fiber/v2" "github.com/samber/lo" @@ -29,8 +28,8 @@ func preConnect(c *fiber.Ctx) error { user := c.Locals("principal").(models.Account) - var session models.AuthSession - if err := database.C.Where(&models.AuthSession{ + var session models.AuthTicket + if err := database.C.Where(&models.AuthTicket{ AccountID: user.ID, ClientID: &client.ID, }).Where("last_grant_at IS NULL").First(&session).Error; err == nil { @@ -40,7 +39,7 @@ func preConnect(c *fiber.Ctx) error { "session": nil, }) } else { - session, err = security.RegenSession(session) + session, err = services.RegenSession(session) } return c.JSON(fiber.Map{ @@ -73,13 +72,11 @@ func doConnect(c *fiber.Ctx) error { switch response { case "code": // OAuth Authorization Mode - session, err := security.GrantOauthSession( + ticket, err := services.NewOauthTicket( user, client, strings.Split(scope, " "), []string{"passport", client.Alias}, - nil, - lo.ToPtr(time.Now()), c.IP(), c.Get(fiber.HeaderUserAgent), ) @@ -89,26 +86,24 @@ func doConnect(c *fiber.Ctx) error { } else { services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent)) return c.JSON(fiber.Map{ - "session": session, + "session": ticket, "redirect_uri": redirect, }) } case "token": // OAuth Implicit Mode - session, err := security.GrantOauthSession( + ticket, err := services.NewOauthTicket( user, client, strings.Split(scope, " "), []string{"passport", client.Alias}, - nil, - lo.ToPtr(time.Now()), c.IP(), c.Get(fiber.HeaderUserAgent), ) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } else if access, refresh, err := security.GetToken(session); err != nil { + } else if access, refresh, err := services.GetToken(ticket); err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } else { services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent)) @@ -116,7 +111,7 @@ func doConnect(c *fiber.Ctx) error { "access_token": access, "refresh_token": refresh, "redirect_uri": redirect, - "session": session, + "ticket": ticket, }) } default: diff --git a/pkg/server/security_api.go b/pkg/server/security_api.go index d9a6730..f5a442f 100644 --- a/pkg/server/security_api.go +++ b/pkg/server/security_api.go @@ -6,52 +6,23 @@ import ( "github.com/gofiber/fiber/v2" ) -func getChallenges(c *fiber.Ctx) error { +func getTickets(c *fiber.Ctx) error { user := c.Locals("principal").(models.Account) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) var count int64 - var challenges []models.AuthChallenge + var sessions []models.AuthTicket if err := database.C. - Where(&models.AuthChallenge{AccountID: user.ID}). - Model(&models.AuthChallenge{}). + Where(&models.AuthTicket{AccountID: user.ID}). + Model(&models.AuthTicket{}). Count(&count).Error; err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } if err := database.C. Order("created_at desc"). - Where(&models.AuthChallenge{AccountID: user.ID}). - Limit(take). - Offset(offset). - Find(&challenges).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - return c.JSON(fiber.Map{ - "count": count, - "data": challenges, - }) -} - -func getSessions(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) - take := c.QueryInt("take", 0) - offset := c.QueryInt("offset", 0) - - var count int64 - var sessions []models.AuthSession - if err := database.C. - Where(&models.AuthSession{AccountID: user.ID}). - Model(&models.AuthSession{}). - Count(&count).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - if err := database.C. - Order("created_at desc"). - Where(&models.AuthSession{AccountID: user.ID}). + Where(&models.AuthTicket{AccountID: user.ID}). Limit(take). Offset(offset). Find(&sessions).Error; err != nil { diff --git a/pkg/server/startup.go b/pkg/server/startup.go index c727925..186d5ac 100644 --- a/pkg/server/startup.go +++ b/pkg/server/startup.go @@ -87,8 +87,7 @@ func NewServer() { me.Put("/", authMiddleware, editUserinfo) me.Put("/page", authMiddleware, editPersonalPage) me.Get("/events", authMiddleware, getEvents) - me.Get("/challenges", authMiddleware, getChallenges) - me.Get("/sessions", authMiddleware, getSessions) + me.Get("/tickets", authMiddleware, getTickets) me.Delete("/sessions/:sessionId", authMiddleware, killSession) me.Post("/confirm", doRegisterConfirm) @@ -112,9 +111,8 @@ func NewServer() { api.Post("/users", doRegister) - api.Put("/auth", startChallenge) - api.Post("/auth", doChallenge) - api.Post("/auth/token", exchangeToken) + api.Post("/auth", doAuthenticate) + api.Post("/auth/token", getToken) api.Post("/auth/factors/:factorId", requestFactorToken) api.Get("/auth/o/connect", authMiddleware, preConnect) diff --git a/pkg/server/userinfo.go b/pkg/server/userinfo_api.go similarity index 100% rename from pkg/server/userinfo.go rename to pkg/server/userinfo_api.go diff --git a/pkg/services/accounts.go b/pkg/services/accounts.go index 44fec1e..63801aa 100644 --- a/pkg/services/accounts.go +++ b/pkg/services/accounts.go @@ -6,7 +6,6 @@ import ( "git.solsynth.dev/hydrogen/passport/pkg/database" "git.solsynth.dev/hydrogen/passport/pkg/models" - "git.solsynth.dev/hydrogen/passport/pkg/security" "github.com/google/uuid" "github.com/samber/lo" "gorm.io/gorm" @@ -23,14 +22,14 @@ func GetAccount(id uint) (models.Account, error) { return account, nil } -func LookupAccount(id string) (models.Account, error) { +func LookupAccount(probe string) (models.Account, error) { var account models.Account - if err := database.C.Where(models.Account{Name: id}).First(&account).Error; err == nil { + if err := database.C.Where(models.Account{Name: probe}).First(&account).Error; err == nil { return account, nil } var contact models.AccountContact - if err := database.C.Where(models.AccountContact{Content: id}).First(&contact).Error; err == nil { + if err := database.C.Where(models.AccountContact{Content: probe}).First(&contact).Error; err == nil { if err := database.C. Where(models.Account{ BaseModel: models.BaseModel{ID: contact.AccountID}, @@ -52,7 +51,7 @@ func CreateAccount(name, nick, email, password string) (models.Account, error) { Factors: []models.AuthFactor{ { Type: models.PasswordAuthFactor, - Secret: security.HashPassword(password), + Secret: HashPassword(password), }, { Type: models.EmailPasswordFactor, diff --git a/pkg/services/auth.go b/pkg/services/auth.go index 250e7b3..6eb22c0 100644 --- a/pkg/services/auth.go +++ b/pkg/services/auth.go @@ -6,7 +6,6 @@ import ( "git.solsynth.dev/hydrogen/passport/pkg/database" "git.solsynth.dev/hydrogen/passport/pkg/models" - "git.solsynth.dev/hydrogen/passport/pkg/security" "github.com/gofiber/fiber/v2" jsoniter "github.com/json-iterator/go" "github.com/rs/zerolog/log" @@ -16,12 +15,12 @@ import ( const authContextBucket = "AuthContext" func Authenticate(access, refresh string, depth int) (user models.Account, newAccess, newRefresh string, err error) { - var claims security.PayloadClaims - claims, err = security.DecodeJwt(access) + var claims PayloadClaims + claims, err = DecodeJwt(access) if err != nil { if len(refresh) > 0 && depth < 1 { // Auto refresh and retry - newAccess, newRefresh, err = security.RefreshToken(refresh) + newAccess, newRefresh, err = RefreshToken(refresh) if err == nil { return Authenticate(newAccess, newRefresh, depth+1) } @@ -74,7 +73,7 @@ func GetAuthContext(jti string) (models.AuthContext, error) { }) if err == nil && time.Now().Unix() >= ctx.ExpiredAt.Unix() { - RevokeAuthContext(jti) + _ = RevokeAuthContext(jti) return ctx, fmt.Errorf("auth context has been expired") } @@ -86,7 +85,7 @@ func GrantAuthContext(jti string) (models.AuthContext, error) { var ctx models.AuthContext // Query data from primary database - session, err := LookupSessionWithToken(jti) + session, err := GetTicketWithToken(jti) if err != nil { return ctx, fmt.Errorf("invalid auth session: %v", err) } else if err := session.IsAvailable(); err != nil { @@ -101,7 +100,7 @@ func GrantAuthContext(jti string) (models.AuthContext, error) { // Every context should expires in some while // Once user update their account info, this will have delay to update ctx = models.AuthContext{ - Session: session, + Ticket: session, Account: user, ExpiredAt: time.Now().Add(5 * time.Minute), } diff --git a/pkg/services/challanges.go b/pkg/services/challanges.go deleted file mode 100644 index 4b33a20..0000000 --- a/pkg/services/challanges.go +++ /dev/null @@ -1,26 +0,0 @@ -package services - -import ( - "git.solsynth.dev/hydrogen/passport/pkg/database" - "git.solsynth.dev/hydrogen/passport/pkg/models" -) - -func LookupChallenge(id uint) (models.AuthChallenge, error) { - var challenge models.AuthChallenge - err := database.C.Where(models.AuthChallenge{ - BaseModel: models.BaseModel{ID: id}, - }).First(&challenge).Error - - return challenge, err -} - -func LookupChallengeWithFingerprint(id uint, ip string, ua string) (models.AuthChallenge, error) { - var challenge models.AuthChallenge - err := database.C.Where(models.AuthChallenge{ - BaseModel: models.BaseModel{ID: id}, - IpAddress: ip, - UserAgent: ua, - }).First(&challenge).Error - - return challenge, err -} diff --git a/pkg/security/encryptor.go b/pkg/services/encryptor.go similarity index 94% rename from pkg/security/encryptor.go rename to pkg/services/encryptor.go index 6cebde0..8700731 100644 --- a/pkg/security/encryptor.go +++ b/pkg/services/encryptor.go @@ -1,4 +1,4 @@ -package security +package services import "golang.org/x/crypto/bcrypt" diff --git a/pkg/services/factors.go b/pkg/services/factors.go index f7a6b41..011aa02 100644 --- a/pkg/services/factors.go +++ b/pkg/services/factors.go @@ -2,6 +2,7 @@ package services import ( "fmt" + "github.com/samber/lo" "git.solsynth.dev/hydrogen/passport/pkg/database" "git.solsynth.dev/hydrogen/passport/pkg/models" @@ -24,7 +25,17 @@ Thank you for your cooperation in helping us maintain the security of your accou Best regards, %s` -func LookupFactor(id uint) (models.AuthFactor, error) { +func GetPasswordFactor(userId uint) (models.AuthFactor, error) { + var factor models.AuthFactor + err := database.C.Where(models.AuthFactor{ + Type: models.PasswordAuthFactor, + AccountID: userId, + }).First(&factor).Error + + return factor, err +} + +func GetFactor(id uint) (models.AuthFactor, error) { var factor models.AuthFactor err := database.C.Where(models.AuthFactor{ BaseModel: models.BaseModel{ID: id}, @@ -33,10 +44,10 @@ func LookupFactor(id uint) (models.AuthFactor, error) { return factor, err } -func LookupFactorsByUser(uid uint) ([]models.AuthFactor, error) { +func ListUserFactor(userId uint) ([]models.AuthFactor, error) { var factors []models.AuthFactor err := database.C.Where(models.AuthFactor{ - AccountID: uid, + AccountID: userId, }).Find(&factors).Error return factors, err @@ -68,3 +79,22 @@ func GetFactorCode(factor models.AuthFactor) (bool, error) { return false, nil } } + +func CheckFactor(factor models.AuthFactor, code string) error { + switch factor.Type { + case models.PasswordAuthFactor: + return lo.Ternary( + VerifyPassword(code, factor.Secret), + nil, + fmt.Errorf("invalid password"), + ) + case models.EmailPasswordFactor: + return lo.Ternary( + code == factor.Secret, + nil, + fmt.Errorf("invalid verification code"), + ) + } + + return nil +} diff --git a/pkg/security/jwt.go b/pkg/services/jwt.go similarity index 99% rename from pkg/security/jwt.go rename to pkg/services/jwt.go index 8d77545..de83bd5 100644 --- a/pkg/security/jwt.go +++ b/pkg/services/jwt.go @@ -1,4 +1,4 @@ -package security +package services import ( "fmt" diff --git a/pkg/services/sessions.go b/pkg/services/ticker_maintainer.go similarity index 80% rename from pkg/services/sessions.go rename to pkg/services/ticker_maintainer.go index 47b0347..487398e 100644 --- a/pkg/services/sessions.go +++ b/pkg/services/ticker_maintainer.go @@ -1,28 +1,15 @@ package services import ( - "time" - "git.solsynth.dev/hydrogen/passport/pkg/database" "git.solsynth.dev/hydrogen/passport/pkg/models" jsoniter "github.com/json-iterator/go" "github.com/rs/zerolog/log" "github.com/spf13/viper" "go.etcd.io/bbolt" + "time" ) -func LookupSessionWithToken(tokenId string) (models.AuthSession, error) { - var session models.AuthSession - if err := database.C. - Where(models.AuthSession{AccessToken: tokenId}). - Or(models.AuthSession{RefreshToken: tokenId}). - First(&session).Error; err != nil { - return session, err - } - - return session, nil -} - func DoAutoSignoff() { duration := time.Duration(viper.GetInt64("security.auto_signoff_duration")) * time.Second divider := time.Now().Add(-duration) @@ -31,7 +18,7 @@ func DoAutoSignoff() { if tx := database.C. Where("last_grant_at < ?", divider). - Delete(&models.AuthSession{}); tx.Error != nil { + Delete(&models.AuthTicket{}); tx.Error != nil { log.Error().Err(tx.Error).Msg("An error occurred when running auto sign off...") } else { log.Debug().Int64("affected", tx.RowsAffected).Msg("Auto sign off accomplished.") diff --git a/pkg/services/ticket.go b/pkg/services/ticket.go new file mode 100644 index 0000000..5379a2e --- /dev/null +++ b/pkg/services/ticket.go @@ -0,0 +1,136 @@ +package services + +import ( + "fmt" + "time" + + "github.com/google/uuid" + + "git.solsynth.dev/hydrogen/passport/pkg/database" + "git.solsynth.dev/hydrogen/passport/pkg/models" + "github.com/samber/lo" +) + +func DetectRisk(user models.Account, ip, ua string) bool { + var secureFactor int64 + if err := database.C.Where(models.AuthTicket{ + AccountID: user.ID, + IpAddress: ip, + }).Model(models.AuthTicket{}).Count(&secureFactor).Error; err == nil { + if secureFactor >= 1 { + return false + } + } + + return true +} + +func NewTicket(user models.Account, ip, ua string) (models.AuthTicket, error) { + var ticket models.AuthTicket + if err := database.C.Where(models.AuthTicket{ + AccountID: user.ID, + }).First(&ticket).Error; err == nil { + return ticket, nil + } + + ticket = models.AuthTicket{ + Claims: []string{"*"}, + Audiences: []string{"passport"}, + IpAddress: ip, + UserAgent: ua, + RequireMFA: DetectRisk(user, ip, ua), + ExpiredAt: lo.ToPtr(time.Now().Add(2 * time.Hour)), + AvailableAt: nil, + AccountID: user.ID, + } + + err := database.C.Save(&ticket).Error + + return ticket, err +} + +func NewOauthTicket( + user models.Account, + client models.ThirdClient, + claims, audiences []string, + ip, ua string, +) (models.AuthTicket, error) { + ticket := models.AuthTicket{ + Claims: claims, + Audiences: audiences, + IpAddress: ip, + UserAgent: ua, + RequireMFA: DetectRisk(user, ip, ua), + GrantToken: lo.ToPtr(uuid.NewString()), + AccessToken: lo.ToPtr(uuid.NewString()), + RefreshToken: lo.ToPtr(uuid.NewString()), + AvailableAt: lo.ToPtr(time.Now()), + ExpiredAt: lo.ToPtr(time.Now()), + ClientID: &client.ID, + AccountID: user.ID, + } + + if err := database.C.Save(&ticket).Error; err != nil { + return ticket, err + } + + return ticket, nil +} + +func ActiveTicketWithPassword(ticket models.AuthTicket, password string) (models.AuthTicket, error) { + if ticket.AvailableAt != nil { + return ticket, nil + } else if !ticket.RequireAuthenticate { + return ticket, fmt.Errorf("detected risk, multi factor authentication required") + } + + if factor, err := GetPasswordFactor(ticket.AccountID); err != nil { + return ticket, fmt.Errorf("unable to active ticket: %v", err) + } else if err = CheckFactor(factor, password); err != nil { + return ticket, err + } + + ticket.AvailableAt = lo.ToPtr(time.Now()) + + if !ticket.RequireAuthenticate && !ticket.RequireMFA { + ticket.AvailableAt = lo.ToPtr(time.Now()) + } + + if err := database.C.Save(&ticket).Error; err != nil { + return ticket, err + } + + return ticket, nil +} + +func ActiveTicketWithMFA(ticket models.AuthTicket, factor models.AuthFactor, code string) (models.AuthTicket, error) { + if ticket.AvailableAt != nil { + return ticket, nil + } else if !ticket.RequireMFA { + return ticket, nil + } + + if err := CheckFactor(factor, code); err != nil { + return ticket, fmt.Errorf("invalid code: %v", err) + } + + ticket.RequireMFA = false + + if !ticket.RequireAuthenticate && !ticket.RequireMFA { + ticket.AvailableAt = lo.ToPtr(time.Now()) + } + + if err := database.C.Save(&ticket).Error; err != nil { + return ticket, err + } + + return ticket, nil +} + +func RegenSession(session models.AuthTicket) (models.AuthTicket, error) { + session.GrantToken = lo.ToPtr(uuid.NewString()) + session.AccessToken = lo.ToPtr(uuid.NewString()) + session.RefreshToken = lo.ToPtr(uuid.NewString()) + err := database.C.Save(&session).Error + return session, err +} diff --git a/pkg/services/ticket_queries.go b/pkg/services/ticket_queries.go new file mode 100644 index 0000000..6412868 --- /dev/null +++ b/pkg/services/ticket_queries.go @@ -0,0 +1,29 @@ +package services + +import ( + "git.solsynth.dev/hydrogen/passport/pkg/database" + "git.solsynth.dev/hydrogen/passport/pkg/models" +) + +func GetTicket(id uint) (models.AuthTicket, error) { + var ticket models.AuthTicket + if err := database.C. + Where(&models.AuthTicket{BaseModel: models.BaseModel{ID: id}}). + First(&ticket).Error; err != nil { + return ticket, err + } + + return ticket, nil +} + +func GetTicketWithToken(tokenId string) (models.AuthTicket, error) { + var ticket models.AuthTicket + if err := database.C. + Where(models.AuthTicket{AccessToken: &tokenId}). + Or(models.AuthTicket{RefreshToken: &tokenId}). + First(&ticket).Error; err != nil { + return ticket, err + } + + return ticket, nil +} diff --git a/pkg/services/ticket_token.go b/pkg/services/ticket_token.go new file mode 100644 index 0000000..7e08998 --- /dev/null +++ b/pkg/services/ticket_token.go @@ -0,0 +1,98 @@ +package services + +import ( + "fmt" + "git.solsynth.dev/hydrogen/passport/pkg/database" + "git.solsynth.dev/hydrogen/passport/pkg/models" + "github.com/samber/lo" + "github.com/spf13/viper" + "strconv" + "time" +) + +func GetToken(ticket models.AuthTicket) (string, string, error) { + var refresh, access string + if err := ticket.IsAvailable(); err != nil { + return refresh, access, err + } + if ticket.AccessToken == nil || ticket.RefreshToken == nil { + return refresh, access, fmt.Errorf("unable to encode token, access or refresh token id missing") + } + + accessDuration := time.Duration(viper.GetInt64("access_token_duration")) * time.Second + refreshDuration := time.Duration(viper.GetInt64("refresh_token_duration")) * time.Second + + var err error + sub := strconv.Itoa(int(ticket.AccountID)) + sed := strconv.Itoa(int(ticket.ID)) + access, err = EncodeJwt(*ticket.AccessToken, JwtAccessType, sub, sed, ticket.Audiences, time.Now().Add(accessDuration)) + if err != nil { + return refresh, access, err + } + refresh, err = EncodeJwt(*ticket.RefreshToken, JwtRefreshType, sub, sed, ticket.Audiences, time.Now().Add(refreshDuration)) + if err != nil { + return refresh, access, err + } + + ticket.LastGrantAt = lo.ToPtr(time.Now()) + database.C.Save(&ticket) + + return access, refresh, nil +} + +func ExchangeToken(token string) (string, string, error) { + var ticket models.AuthTicket + if err := database.C.Where(models.AuthTicket{GrantToken: &token}).First(&ticket).Error; err != nil { + return "", "", err + } else if ticket.LastGrantAt != nil { + return "", "", fmt.Errorf("ticket was granted the first token, use refresh token instead") + } else if len(ticket.Audiences) > 1 { + return "", "", fmt.Errorf("should use authorization code grant type") + } + + return GetToken(ticket) +} + +func ExchangeOauthToken(clientId, clientSecret, redirectUri, token string) (string, string, error) { + var client models.ThirdClient + if err := database.C.Where(models.ThirdClient{Alias: clientId}).First(&client).Error; err != nil { + return "", "", err + } else if client.Secret != clientSecret { + return "", "", fmt.Errorf("invalid client secret") + } else if !client.IsDraft && !lo.Contains(client.Callbacks, redirectUri) { + return "", "", fmt.Errorf("invalid redirect uri") + } + + var ticket models.AuthTicket + if err := database.C.Where(models.AuthTicket{GrantToken: &token}).First(&ticket).Error; err != nil { + return "", "", err + } else if ticket.LastGrantAt != nil { + return "", "", fmt.Errorf("ticket was granted the first token, use refresh token instead") + } + + return GetToken(ticket) +} + +func RefreshToken(token string) (string, string, error) { + parseInt := func(str string) int { + val, _ := strconv.Atoi(str) + return val + } + + var ticket models.AuthTicket + if claims, err := DecodeJwt(token); err != nil { + return "404", "403", err + } else if claims.Type != JwtRefreshType { + return "404", "403", fmt.Errorf("invalid token type, expected refresh token") + } else if err := database.C.Where(models.AuthTicket{ + BaseModel: models.BaseModel{ID: uint(parseInt(claims.SessionID))}, + }).First(&ticket).Error; err != nil { + return "404", "403", err + } + + if ticket, err := RegenSession(ticket); err != nil { + return "404", "403", err + } else { + return GetToken(ticket) + } +}