@@ -4,7 +4,7 @@ import { ServerState } from "./ServerState";
44import { BodyFormat , ParsedRequest , RouteMatch , Router , ServerRequest , Streamer , StreamerHeadersInput , SuperHeadersInit , SuperHeadersPropertyInit , truthy } from "@tiddlywiki/server" ;
55import { SendError , SendErrorReasonData } from "@tiddlywiki/server" ;
66import { ServerToReactAdmin } from './services/setupDevServer' ;
7- import { AuthUser } from './services /sessions' ;
7+ import { AuthUser } from './new-managers /sessions' ;
88
99
1010declare module "@tiddlywiki/server" {
@@ -60,13 +60,13 @@ export class StateObject<
6060
6161 okUser ( ) {
6262 if ( ! this . user . isLoggedIn )
63- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "User not authenticated" } )
63+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "User not authenticated" } )
6464 }
6565 okAdmin ( ) {
66- if ( ! this . user . isLoggedIn )
67- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "User not authenticated" } )
68- if ( ! this . user . isAdmin )
69- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "User is not an admin" } )
66+ if ( ! this . user . isLoggedIn )
67+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "User not authenticated" } )
68+ if ( ! this . user . isAdmin )
69+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "User is not an admin" } )
7070 }
7171
7272 async $transaction < T > ( fn : ( prisma : PrismaTxnClient ) => Promise < T > ) : Promise < T > {
@@ -81,32 +81,47 @@ export class StateObject<
8181 return this . engine . $transaction ( arg ( this . engine ) , options ) ;
8282 }
8383
84+ /**
85+ * This is intended to prevent malicious code attempting to access restricted
86+ * bags using the credentials of more privelaged users and then saving the data
87+ * to less restricted bags. Eventually this is intended to have a more complete
88+ * system where a page requests permission to access another page on behalf of the user.
89+ */
8490 assertWikiReferer ( recipe_slug : string ) {
8591 const state = this ;
8692 if ( ! state . headers . referer ) return ;
8793 const referer = new URL ( state . headers . referer ) ;
88- // console.log("Referer", state.headers.referer, referer);
94+ // for now pages outside the path prefix are denied, but this should probably change
8995 if ( ! referer . pathname . startsWith ( state . pathPrefix ) )
90- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
96+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
97+ // if a recipe endpoint somehow serves a page, it's definitely wiki content, so deny it
98+ if ( referer . pathname . startsWith ( state . pathPrefix + "/recipe/" ) )
99+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
100+ // pages outside the wiki path are allowed to access wiki endpoints if they want
91101 if ( ! referer . pathname . startsWith ( state . pathPrefix + "/wiki/" ) )
92- return ; // keep going
102+ return ;
93103 // we now get the recipe name from the referer
94104 const recipe_name = referer . pathname . substring ( state . pathPrefix . length + "/wiki/" . length ) ;
95105 const referer_slug = decodeURIComponent ( recipe_name ) as PrismaField < "Recipe" , "id" > ;
96106 if ( referer_slug !== recipe_slug )
97- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
107+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
98108 }
99109
100- assertAdminReferer ( ) {
110+ /**
111+ * If this throws in the wrong situation it may be a bug.
112+ * Normally this is intended to keep wiki code from trying to acces admin or login paths,
113+ * since malicious code would be accessing it from every computer that opens the wiki.
114+ * It is not intended to restrict legitimate scenarios, especially not scenarios coded into
115+ * the admin-vanilla client. If it throws under stock conditions, it's a bug.
116+ */
117+ assertRefererPrefix ( prefix : string [ ] ) {
101118 const state = this ;
102119 // referer is a voluntary header
103120 if ( ! state . headers . referer ) return ;
104121 const referer = new URL ( state . headers . referer ) ;
105122 // deny referers from outside our pathprefix
106- if ( ! referer . pathname . startsWith ( state . pathPrefix ) )
107- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
108- if ( referer . pathname . startsWith ( state . pathPrefix + "/wiki/" ) )
109- throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
123+ if ( ! prefix . some ( e => referer . pathname . startsWith ( state . pathPrefix + e ) ) )
124+ throw new SendError ( "ACCESS_DENIED" , 403 , { reason : "Referer check failed" } )
110125 }
111126
112127
0 commit comments