@@ -4,6 +4,8 @@ import { homedir } from "node:os";
44
55export type JsonObject = Record < string , unknown > ;
66
7+ const UNSAFE_CONFIG_KEYS = new Set ( [ "__proto__" , "prototype" , "constructor" ] ) ;
8+
79export const defaultConfig : JsonObject = {
810 waiting : {
911 arcade : {
@@ -40,17 +42,23 @@ export function writeConfig(config: JsonObject) {
4042}
4143
4244export function getConfigValue ( path : string , config = readConfig ( ) ) {
43- return path . split ( "." ) . reduce < unknown > ( ( current , key ) => ( isObject ( current ) ? current [ key ] : undefined ) , config ) ;
45+ return path . split ( "." ) . reduce < unknown > ( ( current , key ) => {
46+ if ( UNSAFE_CONFIG_KEYS . has ( key ) || ! isObject ( current ) || ! Object . hasOwn ( current , key ) ) {
47+ return undefined ;
48+ }
49+ return current [ key ] ;
50+ } , config ) ;
4451}
4552
4653export function setConfigValue ( path : string , rawValue : string , config = readConfig ( ) ) {
4754 const parts = path . split ( "." ) . filter ( Boolean ) ;
4855 if ( parts . length === 0 ) {
4956 throw new Error ( "Config path cannot be empty." ) ;
5057 }
58+ parts . forEach ( assertSafeConfigKey ) ;
5159 let current : JsonObject = config ;
5260 for ( const part of parts . slice ( 0 , - 1 ) ) {
53- if ( ! isObject ( current [ part ] ) ) {
61+ if ( ! Object . hasOwn ( current , part ) || ! isObject ( current [ part ] ) ) {
5462 current [ part ] = { } ;
5563 }
5664 current = current [ part ] as JsonObject ;
@@ -71,9 +79,10 @@ export function parseConfigValue(value: string): unknown {
7179 }
7280}
7381
74- function mergeConfig ( base : JsonObject , override : JsonObject ) : JsonObject {
82+ export function mergeConfig ( base : JsonObject , override : JsonObject ) : JsonObject {
7583 for ( const [ key , value ] of Object . entries ( override ) ) {
76- if ( isObject ( value ) && isObject ( base [ key ] ) ) {
84+ assertSafeConfigKey ( key ) ;
85+ if ( isObject ( value ) && Object . hasOwn ( base , key ) && isObject ( base [ key ] ) ) {
7786 base [ key ] = mergeConfig ( base [ key ] as JsonObject , value ) ;
7887 } else {
7988 base [ key ] = value ;
@@ -85,3 +94,9 @@ function mergeConfig(base: JsonObject, override: JsonObject): JsonObject {
8594function isObject ( value : unknown ) : value is JsonObject {
8695 return typeof value === "object" && value !== null && ! Array . isArray ( value ) ;
8796}
97+
98+ function assertSafeConfigKey ( key : string ) {
99+ if ( UNSAFE_CONFIG_KEYS . has ( key ) ) {
100+ throw new Error ( `Unsafe config key: ${ key } ` ) ;
101+ }
102+ }
0 commit comments