2025-07-19 14:10:33 +08:00
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object . defineProperty ;
var __getOwnPropDesc = Object . getOwnPropertyDescriptor ;
var __getOwnPropNames = Object . getOwnPropertyNames ;
var __hasOwnProp = Object . prototype . hasOwnProperty ;
var __export = ( target , all ) => {
for ( var name in all )
__defProp ( target , name , { get : all [ name ], enumerable : true });
};
var __copyProps = ( to , from , except , desc ) => {
if ( from && typeof from === "object" || typeof from === "function" ) {
for ( let key of __getOwnPropNames ( from ))
if ( ! __hasOwnProp . call ( to , key ) && key !== except )
__defProp ( to , key , { get : () => from [ key ], enumerable : ! ( desc = __getOwnPropDesc ( from , key )) || desc . enumerable });
}
return to ;
};
var __toCommonJS = ( mod ) => __copyProps ( __defProp ({}, "__esModule" , { value : true }), mod );
// main.ts
var main_exports = {};
__export ( main_exports , {
default : () => PasswordPlugin
});
module . exports = __toCommonJS ( main_exports );
var import_obsidian2 = require ( "obsidian" );
// node_modules/mustache/mustache.mjs
var objectToString = Object . prototype . toString ;
var isArray = Array . isArray || function isArrayPolyfill ( object ) {
return objectToString . call ( object ) === "[object Array]" ;
};
function isFunction ( object ) {
return typeof object === "function" ;
}
function typeStr ( obj ) {
return isArray ( obj ) ? "array" : typeof obj ;
}
function escapeRegExp ( string ) {
return string . replace ( /[\-\[\]{}()*+?.,\\\^$|#\s]/g , "\\$&" );
}
function hasProperty ( obj , propName ) {
return obj != null && typeof obj === "object" && propName in obj ;
}
function primitiveHasOwnProperty ( primitive , propName ) {
return primitive != null && typeof primitive !== "object" && primitive . hasOwnProperty && primitive . hasOwnProperty ( propName );
}
var regExpTest = RegExp . prototype . test ;
function testRegExp ( re , string ) {
return regExpTest . call ( re , string );
}
var nonSpaceRe = /\S/ ;
function isWhitespace ( string ) {
return ! testRegExp ( nonSpaceRe , string );
}
var entityMap = {
"&" : "&" ,
"<" : "<" ,
">" : ">" ,
'"' : """ ,
"'" : "'" ,
"/" : "/" ,
"`" : "`" ,
"=" : "="
};
function escapeHtml ( string ) {
return String ( string ). replace ( /[&<>"'`=\/]/g , function fromEntityMap ( s ) {
return entityMap [ s ];
});
}
var whiteRe = /\s*/ ;
var spaceRe = /\s+/ ;
var equalsRe = /\s*=/ ;
var curlyRe = /\s*\}/ ;
var tagRe = /#|\^|\/|>|\{|&|=|!/ ;
function parseTemplate ( template , tags ) {
if ( ! template )
return [];
var lineHasNonSpace = false ;
var sections = [];
var tokens = [];
var spaces = [];
var hasTag = false ;
var nonSpace = false ;
var indentation = "" ;
var tagIndex = 0 ;
function stripSpace () {
if ( hasTag && ! nonSpace ) {
while ( spaces . length )
delete tokens [ spaces . pop ()];
} else {
spaces = [];
}
hasTag = false ;
nonSpace = false ;
}
var openingTagRe , closingTagRe , closingCurlyRe ;
function compileTags ( tagsToCompile ) {
if ( typeof tagsToCompile === "string" )
tagsToCompile = tagsToCompile . split ( spaceRe , 2 );
if ( ! isArray ( tagsToCompile ) || tagsToCompile . length !== 2 )
throw new Error ( "Invalid tags: " + tagsToCompile );
openingTagRe = new RegExp ( escapeRegExp ( tagsToCompile [ 0 ]) + "\\s*" );
closingTagRe = new RegExp ( "\\s*" + escapeRegExp ( tagsToCompile [ 1 ]));
closingCurlyRe = new RegExp ( "\\s*" + escapeRegExp ( "}" + tagsToCompile [ 1 ]));
}
compileTags ( tags || mustache . tags );
var scanner = new Scanner ( template );
var start , type , value , chr , token , openSection ;
while ( ! scanner . eos ()) {
start = scanner . pos ;
value = scanner . scanUntil ( openingTagRe );
if ( value ) {
for ( var i = 0 , valueLength = value . length ; i < valueLength ; ++ i ) {
chr = value . charAt ( i );
if ( isWhitespace ( chr )) {
spaces . push ( tokens . length );
indentation += chr ;
} else {
nonSpace = true ;
lineHasNonSpace = true ;
indentation += " " ;
}
tokens . push ([ "text" , chr , start , start + 1 ]);
start += 1 ;
if ( chr === "\n" ) {
stripSpace ();
indentation = "" ;
tagIndex = 0 ;
lineHasNonSpace = false ;
}
}
}
if ( ! scanner . scan ( openingTagRe ))
break ;
hasTag = true ;
type = scanner . scan ( tagRe ) || "name" ;
scanner . scan ( whiteRe );
if ( type === "=" ) {
value = scanner . scanUntil ( equalsRe );
scanner . scan ( equalsRe );
scanner . scanUntil ( closingTagRe );
} else if ( type === "{" ) {
value = scanner . scanUntil ( closingCurlyRe );
scanner . scan ( curlyRe );
scanner . scanUntil ( closingTagRe );
type = "&" ;
} else {
value = scanner . scanUntil ( closingTagRe );
}
if ( ! scanner . scan ( closingTagRe ))
throw new Error ( "Unclosed tag at " + scanner . pos );
if ( type == ">" ) {
token = [ type , value , start , scanner . pos , indentation , tagIndex , lineHasNonSpace ];
} else {
token = [ type , value , start , scanner . pos ];
}
tagIndex ++ ;
tokens . push ( token );
if ( type === "#" || type === "^" ) {
sections . push ( token );
} else if ( type === "/" ) {
openSection = sections . pop ();
if ( ! openSection )
throw new Error ( 'Unopened section "' + value + '" at ' + start );
if ( openSection [ 1 ] !== value )
throw new Error ( 'Unclosed section "' + openSection [ 1 ] + '" at ' + start );
} else if ( type === "name" || type === "{" || type === "&" ) {
nonSpace = true ;
} else if ( type === "=" ) {
compileTags ( value );
}
}
stripSpace ();
openSection = sections . pop ();
if ( openSection )
throw new Error ( 'Unclosed section "' + openSection [ 1 ] + '" at ' + scanner . pos );
return nestTokens ( squashTokens ( tokens ));
}
function squashTokens ( tokens ) {
var squashedTokens = [];
var token , lastToken ;
for ( var i = 0 , numTokens = tokens . length ; i < numTokens ; ++ i ) {
token = tokens [ i ];
if ( token ) {
if ( token [ 0 ] === "text" && lastToken && lastToken [ 0 ] === "text" ) {
lastToken [ 1 ] += token [ 1 ];
lastToken [ 3 ] = token [ 3 ];
} else {
squashedTokens . push ( token );
lastToken = token ;
}
}
}
return squashedTokens ;
}
function nestTokens ( tokens ) {
var nestedTokens = [];
var collector = nestedTokens ;
var sections = [];
var token , section ;
for ( var i = 0 , numTokens = tokens . length ; i < numTokens ; ++ i ) {
token = tokens [ i ];
switch ( token [ 0 ]) {
case "#" :
case "^" :
collector . push ( token );
sections . push ( token );
collector = token [ 4 ] = [];
break ;
case "/" :
section = sections . pop ();
section [ 5 ] = token [ 2 ];
collector = sections . length > 0 ? sections [ sections . length - 1 ][ 4 ] : nestedTokens ;
break ;
default :
collector . push ( token );
}
}
return nestedTokens ;
}
function Scanner ( string ) {
this . string = string ;
this . tail = string ;
this . pos = 0 ;
}
Scanner . prototype . eos = function eos () {
return this . tail === "" ;
};
Scanner . prototype . scan = function scan ( re ) {
var match = this . tail . match ( re );
if ( ! match || match . index !== 0 )
return "" ;
var string = match [ 0 ];
this . tail = this . tail . substring ( string . length );
this . pos += string . length ;
return string ;
};
Scanner . prototype . scanUntil = function scanUntil ( re ) {
var index = this . tail . search ( re ), match ;
switch ( index ) {
case - 1 :
match = this . tail ;
this . tail = "" ;
break ;
case 0 :
match = "" ;
break ;
default :
match = this . tail . substring ( 0 , index );
this . tail = this . tail . substring ( index );
}
this . pos += match . length ;
return match ;
};
function Context ( view , parentContext ) {
this . view = view ;
this . cache = { "." : this . view };
this . parent = parentContext ;
}
Context . prototype . push = function push ( view ) {
return new Context ( view , this );
};
Context . prototype . lookup = function lookup ( name ) {
var cache = this . cache ;
var value ;
if ( cache . hasOwnProperty ( name )) {
value = cache [ name ];
} else {
var context = this , intermediateValue , names , index , lookupHit = false ;
while ( context ) {
if ( name . indexOf ( "." ) > 0 ) {
intermediateValue = context . view ;
names = name . split ( "." );
index = 0 ;
while ( intermediateValue != null && index < names . length ) {
if ( index === names . length - 1 )
lookupHit = hasProperty ( intermediateValue , names [ index ]) || primitiveHasOwnProperty ( intermediateValue , names [ index ]);
intermediateValue = intermediateValue [ names [ index ++ ]];
}
} else {
intermediateValue = context . view [ name ];
lookupHit = hasProperty ( context . view , name );
}
if ( lookupHit ) {
value = intermediateValue ;
break ;
}
context = context . parent ;
}
cache [ name ] = value ;
}
if ( isFunction ( value ))
value = value . call ( this . view );
return value ;
};
function Writer () {
this . templateCache = {
_cache : {},
set : function set ( key , value ) {
this . _cache [ key ] = value ;
},
get : function get ( key ) {
return this . _cache [ key ];
},
clear : function clear () {
this . _cache = {};
}
};
}
Writer . prototype . clearCache = function clearCache () {
if ( typeof this . templateCache !== "undefined" ) {
this . templateCache . clear ();
}
};
Writer . prototype . parse = function parse ( template , tags ) {
var cache = this . templateCache ;
var cacheKey = template + ":" + ( tags || mustache . tags ). join ( ":" );
var isCacheEnabled = typeof cache !== "undefined" ;
var tokens = isCacheEnabled ? cache . get ( cacheKey ) : void 0 ;
if ( tokens == void 0 ) {
tokens = parseTemplate ( template , tags );
isCacheEnabled && cache . set ( cacheKey , tokens );
}
return tokens ;
};
Writer . prototype . render = function render ( template , view , partials , config ) {
var tags = this . getConfigTags ( config );
var tokens = this . parse ( template , tags );
var context = view instanceof Context ? view : new Context ( view , void 0 );
return this . renderTokens ( tokens , context , partials , template , config );
};
Writer . prototype . renderTokens = function renderTokens ( tokens , context , partials , originalTemplate , config ) {
var buffer = "" ;
var token , symbol , value ;
for ( var i = 0 , numTokens = tokens . length ; i < numTokens ; ++ i ) {
value = void 0 ;
token = tokens [ i ];
symbol = token [ 0 ];
if ( symbol === "#" )
value = this . renderSection ( token , context , partials , originalTemplate , config );
else if ( symbol === "^" )
value = this . renderInverted ( token , context , partials , originalTemplate , config );
else if ( symbol === ">" )
value = this . renderPartial ( token , context , partials , config );
else if ( symbol === "&" )
value = this . unescapedValue ( token , context );
else if ( symbol === "name" )
value = this . escapedValue ( token , context , config );
else if ( symbol === "text" )
value = this . rawValue ( token );
if ( value !== void 0 )
buffer += value ;
}
return buffer ;
};
Writer . prototype . renderSection = function renderSection ( token , context , partials , originalTemplate , config ) {
var self = this ;
var buffer = "" ;
var value = context . lookup ( token [ 1 ]);
function subRender ( template ) {
return self . render ( template , context , partials , config );
}
if ( ! value )
return ;
if ( isArray ( value )) {
for ( var j = 0 , valueLength = value . length ; j < valueLength ; ++ j ) {
buffer += this . renderTokens ( token [ 4 ], context . push ( value [ j ]), partials , originalTemplate , config );
}
} else if ( typeof value === "object" || typeof value === "string" || typeof value === "number" ) {
buffer += this . renderTokens ( token [ 4 ], context . push ( value ), partials , originalTemplate , config );
} else if ( isFunction ( value )) {
if ( typeof originalTemplate !== "string" )
throw new Error ( "Cannot use higher-order sections without the original template" );
value = value . call ( context . view , originalTemplate . slice ( token [ 3 ], token [ 5 ]), subRender );
if ( value != null )
buffer += value ;
} else {
buffer += this . renderTokens ( token [ 4 ], context , partials , originalTemplate , config );
}
return buffer ;
};
Writer . prototype . renderInverted = function renderInverted ( token , context , partials , originalTemplate , config ) {
var value = context . lookup ( token [ 1 ]);
if ( ! value || isArray ( value ) && value . length === 0 )
return this . renderTokens ( token [ 4 ], context , partials , originalTemplate , config );
};
Writer . prototype . indentPartial = function indentPartial ( partial , indentation , lineHasNonSpace ) {
var filteredIndentation = indentation . replace ( /[^ \t]/g , "" );
var partialByNl = partial . split ( "\n" );
for ( var i = 0 ; i < partialByNl . length ; i ++ ) {
if ( partialByNl [ i ]. length && ( i > 0 || ! lineHasNonSpace )) {
partialByNl [ i ] = filteredIndentation + partialByNl [ i ];
}
}
return partialByNl . join ( "\n" );
};
Writer . prototype . renderPartial = function renderPartial ( token , context , partials , config ) {
if ( ! partials )
return ;
var tags = this . getConfigTags ( config );
var value = isFunction ( partials ) ? partials ( token [ 1 ]) : partials [ token [ 1 ]];
if ( value != null ) {
var lineHasNonSpace = token [ 6 ];
var tagIndex = token [ 5 ];
var indentation = token [ 4 ];
var indentedValue = value ;
if ( tagIndex == 0 && indentation ) {
indentedValue = this . indentPartial ( value , indentation , lineHasNonSpace );
}
var tokens = this . parse ( indentedValue , tags );
return this . renderTokens ( tokens , context , partials , indentedValue , config );
}
};
Writer . prototype . unescapedValue = function unescapedValue ( token , context ) {
var value = context . lookup ( token [ 1 ]);
if ( value != null )
return value ;
};
Writer . prototype . escapedValue = function escapedValue ( token , context , config ) {
var escape = this . getConfigEscape ( config ) || mustache . escape ;
var value = context . lookup ( token [ 1 ]);
if ( value != null )
return typeof value === "number" && escape === mustache . escape ? String ( value ) : escape ( value );
};
Writer . prototype . rawValue = function rawValue ( token ) {
return token [ 1 ];
};
Writer . prototype . getConfigTags = function getConfigTags ( config ) {
if ( isArray ( config )) {
return config ;
} else if ( config && typeof config === "object" ) {
return config . tags ;
} else {
return void 0 ;
}
};
Writer . prototype . getConfigEscape = function getConfigEscape ( config ) {
if ( config && typeof config === "object" && ! isArray ( config )) {
return config . escape ;
} else {
return void 0 ;
}
};
var mustache = {
name : "mustache.js" ,
version : "4.2.0" ,
tags : [ "{{" , "}}" ],
clearCache : void 0 ,
escape : void 0 ,
parse : void 0 ,
render : void 0 ,
Scanner : void 0 ,
Context : void 0 ,
Writer : void 0 ,
/**
* Allows a user to override the default caching strategy, by providing an
* object with set, get and clear methods. This can also be used to disable
* the cache by setting it to the literal `undefined`.
*/
set templateCache ( cache ) {
defaultWriter . templateCache = cache ;
},
/**
* Gets the default or overridden caching object from the default writer.
*/
get templateCache () {
return defaultWriter . templateCache ;
}
};
var defaultWriter = new Writer ();
mustache . clearCache = function clearCache2 () {
return defaultWriter . clearCache ();
};
mustache . parse = function parse2 ( template , tags ) {
return defaultWriter . parse ( template , tags );
};
mustache . render = function render2 ( template , view , partials , config ) {
if ( typeof template !== "string" ) {
throw new TypeError ( 'Invalid template! Template should be a "string" but "' + typeStr ( template ) + '" was given as the first argument for mustache#render(template, view, partials)' );
}
return defaultWriter . render ( template , view , partials , config );
};
mustache . escape = escapeHtml ;
mustache . Scanner = Scanner ;
mustache . Context = Context ;
mustache . Writer = Writer ;
var mustache_default = mustache ;
// i18n.ts
var import_obsidian = require ( "obsidian" );
// langs/en.json
var en_default = {
ok : "OK" ,
cancel : "Cancel" ,
open : "Lock" ,
close_password_protection : "Unlock password protection" ,
open_password_protection : "Lock password protection" ,
password_protection_opened : "Password protection is locked!" ,
2025-08-03 11:01:42 +08:00
password_protection_closed : "Password verification passed." ,
2025-07-19 14:10:33 +08:00
notice_set_password : "Please set the password in the settings page for the Password Protection Plugin first!" ,
setting_folder_name : "Protected folder or file" ,
2025-10-08 10:49:47 +08:00
setting_folder_desc : "The default value '/' is the root path of the vault" ,
place_holder_enter_path : "Enter path, e.g. mynotes/diary" ,
2025-07-19 14:10:33 +08:00
setting_toggle_name : "Enable/Disable password protection" ,
setting_toggle_desc : "To enable password protection you will set your password, to disable it you will need to verify your password." ,
hint_enter_in_both_boxes : "Please enter your password in both boxes." ,
hint_password_must_match : "Passwords must match." ,
hint_password_length : "Password must contain valid characters and must be 1-20 characters long." ,
hint_password_valid_character : "Password has invalid characters." ,
set_password_title : "Set a password to protect a folder" ,
place_holder_enter_password : "Enter password, 1-20 characters long" ,
confirm_password : "Confirm your password" ,
verify_password : "Verify password" ,
enter_password : "Enter your password" ,
enter_password_to_verify : "Please enter your password to unlock." ,
password_is_empty : "Password is empty." ,
password_not_match : "Password doesn't match." ,
password_is_right : "Password is correct." ,
auto_lock_interval_name : "Auto-lock" ,
auto_lock_interval_desc : "The number of minutes to wait before auto-locking since the protected file was opened." ,
before_open_protection : "Turn on the above switch to enable password protection, and disable the below options." ,
setting_pwd_hint_question_name : "Password prompt" ,
setting_pwd_hint_question_desc : "Please type a question to help you remember your password." ,
place_holder_enter_pwd_hint_question : "Password prompt question" ,
setting_more_path : "More folders or files to be protected (up to 6)" ,
setting_add_path : "Add protected path" ,
setting_add_path_name : "Protected path" ,
2025-10-08 10:49:47 +08:00
setting_add_path_place_holder : "Enter path, e.g. mynotes/diary" ,
2025-07-19 14:10:33 +08:00
setting_remove_path : "Remove protected path"
};
// langs/es.json
var es_default = {
ok : "ACEPTAR" ,
cancel : "Cancelar" ,
open : "Activar" ,
close_password_protection : "Activar protecci\xF3n con contrase\xF1a" ,
open_password_protection : "Desactivar protecci\xF3n con contrase\xF1a" ,
password_protection_opened : "\xA1Protecci\xF3n con contrase\xF1a est\xE1 bloqueada!" ,
2025-08-03 11:01:42 +08:00
password_protection_closed : "Verificaci\xF3n de contrase\xF1a aprobada!" ,
2025-07-19 14:10:33 +08:00
notice_set_password : "\xA1Introduzca la contrase\xF1a en preferencias para el complemento Protecci\xF3n con Contrase\xF1a primero!" ,
setting_folder_name : "Carpeta o archivo protegido" ,
2025-10-08 10:49:47 +08:00
setting_folder_desc : "El valor predeterminado '/' es la ruta ra\xEDz de la b\xF3veda" ,
place_holder_enter_path : "Introduzca la ruta, p. ej. Misnotas/diario" ,
2025-07-19 14:10:33 +08:00
setting_toggle_name : "Activar/Desactivar protecci\xF3n con contrase\xF1a" ,
setting_toggle_desc : "Para activar protecci\xF3n con contrase\xF1a, establecer\xE1s una contrase\xF1a, y para desactivar, tienes que verificarla." ,
hint_enter_in_both_boxes : "Introduzca la contrase\xF1a en ambas casillas." ,
hint_password_must_match : "Contrase\xF1as tienen que coincidir." ,
hint_password_length : "Contrase\xF1a tiene que usar caracteres v\xE1lidos y contener 1-20 caracteres." ,
hint_password_valid_character : "Contrase\xF1a contiene caracteres inv\xE1lidos." ,
set_password_title : "Introduzca una contrase\xF1a para proteger una carpeta" ,
place_holder_enter_password : "Introduce contrase\xF1a, 1-20 caracteres" ,
confirm_password : "Confirmar la contrase\xF1a" ,
verify_password : "Verifique Contrase\xF1a" ,
enter_password : "Introduce la contrase\xF1a" ,
enter_password_to_verify : "Por favor, introduce la contrase\xF1a para desbloquear." ,
password_is_empty : "Contrase\xF1a vac\xEDa." ,
password_not_match : "Contrase\xF1as no coinciden." ,
password_is_right : "Contrase\xF1a correcta." ,
auto_lock_interval_name : "Bloqueo Autom\xE1tico" ,
auto_lock_interval_desc : "El n\xFAmero de minutos para esperar antes de bloquear autom\xE1tico desde que se abri\xF3 la nota protegido." ,
before_open_protection : "Activar el interruptor de arriba para activar protecci\xF3n con contrase\xF1a y desactivar las opciones de abajo." ,
setting_pwd_hint_question_name : "Mensaje para recordar" ,
setting_pwd_hint_question_desc : "Escribe una frase para ayudarte recordar la contrase\xF1a." ,
place_holder_enter_pwd_hint_question : "Mensaje para recordar" ,
setting_more_path : "M\xE1s carpetas o archivos a proteger (hasta 6)" ,
setting_add_path : "A\xF1adir ruta protegida" ,
setting_add_path_name : "Ruta protegida" ,
2025-10-08 10:49:47 +08:00
setting_add_path_place_holder : "Introduzca la ruta, p. ej. Misnotas/diario" ,
2025-07-19 14:10:33 +08:00
setting_remove_path : "Eliminar ruta protegida"
};
// langs/zh_cn.json
var zh_cn_default = {
ok : "\u786E\u5B9A" ,
cancel : "\u53D6\u6D88" ,
2025-08-03 11:01:42 +08:00
open : "\u5F00\u542F\u5BC6\u7801\u4FDD\u62A4" ,
open_password_protection : "\u5F00\u542F\u5BC6\u7801\u4FDD\u62A4" ,
password_protection_opened : "\u5BC6\u7801\u4FDD\u62A4\u5DF2\u5F00\u542F" ,
password_protection_closed : "\u5BC6\u7801\u9A8C\u8BC1\u901A\u8FC7" ,
2025-07-19 14:10:33 +08:00
notice_set_password : "\u8BF7\u5148\u53BB\u5BC6\u7801\u4FDD\u62A4\u63D2\u4EF6\u7684\u8BBE\u7F6E\u9875\u8BBE\u7F6E\u5BC6\u7801" ,
setting_folder_name : "\u9700\u8981\u4FDD\u62A4\u7684\u6587\u4EF6\u5939\u6216\u6587\u4EF6" ,
2025-10-08 10:49:47 +08:00
setting_folder_desc : "\u9ED8\u8BA4\u503C '/' \u4EE3\u8868\u7B14\u8BB0\u5E93\u7684\u6839\u8DEF\u5F84" ,
place_holder_enter_path : "\u8F93\u5165\u8DEF\u5F84\uFF0C\u6BD4\u5982\uFF1A\u6211\u7684\u7B14\u8BB0/\u65E5\u8BB0" ,
2025-07-19 14:10:33 +08:00
setting_toggle_name : "\u5F00\u542F\u6216\u5173\u95ED\u5BC6\u7801\u4FDD\u62A4" ,
setting_toggle_desc : "\u5F00\u542F\u4FDD\u62A4\u9700\u8981\u8BBE\u7F6E\u5BC6\u7801\uFF0C\u5173\u95ED\u4FDD\u62A4\u9700\u8981\u9A8C\u8BC1\u5BC6\u7801" ,
hint_enter_in_both_boxes : "\u8BF7\u5728\u4E24\u4E2A\u8F93\u5165\u6846\u4E2D\u90FD\u8F93\u5165\u5BC6\u7801" ,
hint_password_must_match : "\u8BF7\u5728\u4E24\u4E2A\u8F93\u5165\u6846\u4E2D\u8F93\u5165\u4E00\u6837\u7684\u5BC6\u7801" ,
hint_password_length : "\u5BC6\u7801\u5FC5\u987B\u662F\u6709\u6548\u5B57\u7B26\uFF0C\u957F\u5EA6 1~20 \u4E2A\u5B57\u7B26" ,
hint_password_valid_character : "\u5BC6\u7801\u5FC5\u987B\u662F\u6709\u6548\u5B57\u7B26" ,
set_password_title : "\u8BBE\u7F6E\u5BC6\u7801" ,
place_holder_enter_password : "\u8F93\u5165\u5BC6\u7801, \u957F\u5EA6 1~20 \u4E2A\u5B57\u7B26" ,
confirm_password : "\u518D\u6B21\u8F93\u5165\u5BC6\u7801" ,
verify_password : "\u9A8C\u8BC1\u5BC6\u7801" ,
enter_password : "\u8F93\u5165\u4F60\u7684\u5BC6\u7801" ,
enter_password_to_verify : "\u8BF7\u8F93\u5165\u5BC6\u7801\u9A8C\u8BC1" ,
2025-08-03 11:01:42 +08:00
password_is_empty : "\u5BC6\u7801\u4E0D\u80FD\u662F\u7A7A\u7684\u3002" ,
2025-07-19 14:10:33 +08:00
password_not_match : "\u5BC6\u7801\u4E0D\u5339\u914D\u3002" ,
password_is_right : "\u5BC6\u7801\u6B63\u786E" ,
2025-08-03 11:01:42 +08:00
auto_lock_interval_name : "\u81EA\u52A8\u5F00\u542F\u5BC6\u7801\u4FDD\u62A4\u7684\u95F4\u9694\u65F6\u95F4" ,
auto_lock_interval_desc : "\u4ECE\u4E0A\u6B21\u5173\u95ED\u5BC6\u7801\u4FDD\u62A4\u6216\u4E0A\u6B21\u6253\u5F00\u4E00\u4E2A\u53D7\u4FDD\u62A4\u7684\u6587\u4EF6\u5F00\u59CB\u8BA1\u7B97\uFF0C0 \u4EE3\u8868\u4E0D\u81EA\u52A8\u5F00\u542F\u5BC6\u7801\u4FDD\u62A4, \u5355\u4F4D\uFF1A\u5206\u949F" ,
2025-07-19 14:10:33 +08:00
before_open_protection : "\u6253\u5F00\u4E0A\u9762\u7684\u5BC6\u7801\u4FDD\u62A4\u5F00\u5173\u540E\uFF0C\u4E0B\u9762\u7684\u8BBE\u7F6E\u5C06\u4E0D\u53EF\u4FEE\u6539." ,
setting_pwd_hint_question_name : "\u5BC6\u7801\u63D0\u793A\u95EE\u9898" ,
setting_pwd_hint_question_desc : "\u5F53\u4F60\u5FD8\u8BB0\u5BC6\u7801\u65F6\uFF0C\u53EF\u4EE5\u901A\u8FC7\u8FD9\u4E2A\u95EE\u9898\u6765\u63D0\u793A\u4F60\u7684\u5BC6\u7801." ,
place_holder_enter_pwd_hint_question : "\u8F93\u5165\u5BC6\u7801\u63D0\u793A\u95EE\u9898" ,
setting_more_path : "\u66F4\u591A\u9700\u8981\u4FDD\u62A4\u7684\u6587\u4EF6\u5939\u6216\u6587\u4EF6(\u6700\u591A6\u4E2A)" ,
setting_add_path : "\u6DFB\u52A0\u4FDD\u62A4\u8DEF\u5F84" ,
setting_add_path_name : "\u4FDD\u62A4\u8DEF\u5F84" ,
2025-10-08 10:49:47 +08:00
setting_add_path_place_holder : "\u8F93\u5165\u8DEF\u5F84\uFF0C\u6BD4\u5982\uFF1A\u6211\u7684\u7B14\u8BB0/\u65E5\u8BB0" ,
2025-07-19 14:10:33 +08:00
setting_remove_path : "\u79FB\u9664\u4FDD\u62A4\u8DEF\u5F84"
};
// langs/zh_tw.json
var zh_tw_default = {
ok : "\u78BA\u8A8D" ,
cancel : "\u53D6\u6D88" ,
2025-08-03 11:01:42 +08:00
open : "\u958B\u555F\u5BC6\u78BC\u4FDD\u8B77" ,
open_password_protection : "\u958B\u555F\u5BC6\u78BC\u4FDD\u8B77" ,
password_protection_opened : "\u5BC6\u78BC\u4FDD\u8B77\u5DF2\u958B\u555F" ,
password_protection_closed : "\u5BC6\u78BC\u9A57\u8B49\u901A\u904E" ,
2025-07-19 14:10:33 +08:00
notice_set_password : "\u8ACB\u5148\u53BB\u5BC6\u78BC\u4FDD\u8B77\u63D2\u4EF6\u7684\u8A2D\u7F6E\u9801\u8A2D\u7F6E\u5BC6\u78BC" ,
setting_folder_name : "\u9700\u8981\u4FDD\u8B77\u7684\u6587\u4EF6\u593E\u6216\u6587\u4EF6" ,
2025-10-08 10:49:47 +08:00
setting_folder_desc : "\u9ED8\u8A8D\u503C '/' \u4EE3\u8868\u7B46\u8A18\u5EAB\u7684\u6839\u8DEF\u5F91" ,
place_holder_enter_path : "\u8F38\u5165\u8DEF\u5F91\uFF0C\u6BD4\u5982\uFF1A\u6211\u7684\u7B46\u8A18/\u65E5\u8A18" ,
2025-07-19 14:10:33 +08:00
setting_toggle_name : "\u958B\u555F\u6216\u95DC\u9589\u5BC6\u78BC\u4FDD\u8B77" ,
setting_toggle_desc : "\u958B\u555F\u4FDD\u8B77\u9700\u8981\u8A2D\u7F6E\u5BC6\u78BC\uFF0C\u95DC\u9589\u4FDD\u8B77\u9700\u8981\u9A57\u8B49\u5BC6\u78BC" ,
hint_enter_in_both_boxes : "\u8ACB\u5728\u5169\u500B\u8F38\u5165\u6846\u4E2D\u90FD\u8F38\u5165\u5BC6\u78BC" ,
hint_password_must_match : "\u8ACB\u5728\u5169\u500B\u8F38\u5165\u6846\u4E2D\u8F38\u5165\u4E00\u6A23\u7684\u5BC6\u78BC" ,
hint_password_length : "\u5BC6\u78BC\u5FC5\u9808\u662F\u6709\u6548\u5B57\u7B26\uFF0C\u9577\u5EA6 1~20 \u500B\u5B57\u7B26" ,
hint_password_valid_character : "\u5BC6\u78BC\u5FC5\u9808\u662F\u6709\u6548\u5B57\u7B26" ,
set_password_title : "\u8A2D\u7F6E\u5BC6\u78BC" ,
place_holder_enter_password : "\u8F38\u5165\u5BC6\u78BC\uFF0C\u9577\u5EA6 1~20 \u500B\u5B57\u7B26" ,
confirm_password : "\u518D\u6B21\u8F38\u5165\u5BC6\u78BC" ,
verify_password : "\u9A57\u8B49\u5BC6\u78BC" ,
enter_password : "\u8F38\u5165\u4F60\u7684\u5BC6\u78BC" ,
enter_password_to_verify : "\u8ACB\u8F38\u5165\u5BC6\u78BC\u9A57\u8B49" ,
2025-08-03 11:01:42 +08:00
password_is_empty : "\u5BC6\u78BC\u4E0D\u80FD\u662F\u7A7A\u7684\u3002" ,
2025-07-19 14:10:33 +08:00
password_not_match : "\u5BC6\u78BC\u4E0D\u5339\u914D\u3002" ,
password_is_right : "\u5BC6\u78BC\u6B63\u78BA" ,
2025-08-03 11:01:42 +08:00
auto_lock_interval_name : "\u81EA\u52D5\u958B\u555F\u5BC6\u78BC\u4FDD\u8B77\u7684\u9593\u9694\u6642\u9593" ,
auto_lock_interval_desc : "\u5F9E\u4E0A\u6B21\u95DC\u9589\u5BC6\u78BC\u4FDD\u8B77\u6216\u4E0A\u6B21\u6253\u958B\u4E00\u500B\u53D7\u4FDD\u8B77\u7684\u6587\u4EF6\u958B\u59CB\u8A08\u7B97\uFF0C0 \u8868\u793A\u4E0D\u81EA\u52D5\u958B\u555F\u5BC6\u78BC\u4FDD\u8B77\uFF0C\u55AE\u4F4D\uFF1A\u5206\u9418" ,
2025-07-19 14:10:33 +08:00
before_open_protection : "\u6253\u958B\u4E0A\u9762\u7684\u5BC6\u78BC\u4FDD\u8B77\u958B\u95DC\u540E\uFF0C\u4E0B\u9762\u7684\u8A2D\u7F6E\u5C07\u4E0D\u53EF\u4FEE\u6539." ,
setting_pwd_hint_question_name : "\u5BC6\u78BC\u63D0\u793A\u554F\u984C" ,
setting_pwd_hint_question_desc : "\u7576\u4F60\u5FD8\u8A18\u5BC6\u78BC\u6642\uFF0C\u53EF\u4EE5\u901A\u904E\u9019\u500B\u554F\u984C\u4F86\u63D0\u793A\u4F60\u7684\u5BC6\u78BC." ,
place_holder_enter_pwd_hint_question : "\u8F38\u5165\u5BC6\u78BC\u63D0\u793A\u554F\u984C" ,
setting_more_path : "\u66F4\u591A\u9700\u8981\u4FDD\u8B77\u7684\u6587\u4EF6\u593E\u6216\u6587\u4EF6(\u6700\u591A6\u500B)" ,
setting_add_path : "\u6DFB\u52A0\u4FDD\u8B77\u8DEF\u5F91" ,
setting_add_path_name : "\u4FDD\u8B77\u8DEF\u5F91" ,
2025-10-08 10:49:47 +08:00
setting_add_path_place_holder : "\u8F38\u5165\u8DEF\u5F91\uFF0C\u6BD4\u5982\uFF1A\u6211\u7684\u7B46\u8A18/\u65E5\u8A18" ,
2025-07-19 14:10:33 +08:00
setting_remove_path : "\u79FB\u9664\u4FDD\u8B77\u8DEF\u5F91"
};
// langs/index.ts
var LANGS = {
en : en_default ,
es : es_default ,
zh_cn : zh_cn_default ,
zh_tw : zh_tw_default
};
// i18n.ts
var I18n = class {
constructor ( lang , saveSettingFunc ) {
this . lang = lang ;
this . saveSettingFunc = saveSettingFunc ;
}
async changeTo ( anotherLang ) {
this . lang = anotherLang ;
await this . saveSettingFunc ( anotherLang );
}
_get ( key ) {
let realLang = this . lang ;
if ( this . lang === "auto" && import_obsidian . moment . locale (). replace ( "-" , "_" ) in LANGS ) {
realLang = import_obsidian . moment . locale (). replace ( "-" , "_" );
} else {
realLang = "en" ;
}
const res = LANGS [ realLang ][ key ] || LANGS [ "en" ][ key ] || key ;
return res ;
}
t ( key , vars ) {
if ( vars === void 0 ) {
return this . _get ( key );
}
return mustache_default . render ( this . _get ( key ), vars );
}
};
// main.ts
var ADD_PATH_MAX = 6 ;
var PASSWORD_LENGTH_MIN = 1 ;
var PASSWORD_LENGTH_MAX = 20 ;
var ENCRYPT_KEY = 30 ;
var ROOT_PATH = ( 0 , import_obsidian2 . normalizePath )( "/" );
var SOLID_PASS = "qBjSbeiu2qDNEq5d" ;
var DEFAULT_SETTINGS = {
protectedPath : ROOT_PATH ,
addedProtectedPath : [],
protectEnabled : false ,
password : "" ,
lang : "auto" ,
autoLockInterval : 0 ,
pwdHintQuestion : "" ,
isLastVerifyPasswordCorrect : false ,
timeOnUnload : 0
};
var PasswordPlugin = class extends import_obsidian2 . Plugin {
constructor () {
super (... arguments );
this . isVerifyPasswordWaitting = false ;
this . isVerifyPasswordCorrect = false ;
2025-10-08 10:49:47 +08:00
this . isAutoLockRegistered = false ;
2025-07-19 14:10:33 +08:00
this . lastUnlockOrOpenFileTime = null ;
this . t = ( x , vars ) => {
return this . i18n . t ( x , vars );
};
2025-10-08 10:49:47 +08:00
this . handleRename = ( file , oldPath ) => {
if ( file != null ) {
if ( this . settings . protectEnabled && ! this . isVerifyPasswordCorrect && ( this . isProtectedFile ( oldPath ) || this . isProtectedFile ( file . path ))) {
this . verifyPasswordProtection ();
}
if ( this . settings . protectEnabled && this . isProtectedFile ( oldPath )) {
this . ReplaceProtectedPath ( oldPath , file . path );
}
if ( this . settings . protectEnabled && this . isVerifyPasswordCorrect ) {
this . lastUnlockOrOpenFileTime = ( 0 , import_obsidian2 . moment )();
}
}
};
// process the save event of file modified.
this . handleFileModify = ( file ) => {
this . lastUnlockOrOpenFileTime = ( 0 , import_obsidian2 . moment )();
};
2025-07-19 14:10:33 +08:00
}
async onload () {
await this . loadSettings ();
this . lastUnlockOrOpenFileTime = ( 0 , import_obsidian2 . moment )();
this . settings . protectedPath = this . settings . protectedPath . trim ();
2025-10-08 10:49:47 +08:00
if ( this . settings . protectedPath . length == 0 ) {
this . settings . protectedPath = ROOT_PATH ;
2025-07-19 14:10:33 +08:00
}
if ( this . settings . addedProtectedPath . length > ADD_PATH_MAX ) {
this . settings . addedProtectedPath . slice ( ADD_PATH_MAX , this . settings . addedProtectedPath . length - ADD_PATH_MAX );
}
this . settings . addedProtectedPath = this . settings . addedProtectedPath . filter (( str ) => str . trim () !== "" );
this . i18n = new I18n ( this . settings . lang , async ( lang ) => {
this . settings . lang = lang ;
await this . saveSettings ();
});
2025-08-03 11:01:42 +08:00
this . passwordRibbonBtn = this . addRibbonIcon ( "lock" , this . t ( "open_password_protection" ), ( evt ) => {
this . openPasswordProtection ();
});
2025-07-19 14:10:33 +08:00
this . addCommand ({
id : "Open password protection" ,
name : this . t ( "open" ),
callback : () => {
2025-08-03 11:01:42 +08:00
this . enablePasswordProtection ();
2025-07-19 14:10:33 +08:00
}
});
this . addSettingTab ( new PasswordSettingTab ( this . app , this ));
this . app . workspace . onLayoutReady (() => {
if ( this . settings . protectEnabled && this . isIncludeRootPath ()) {
if ( ! this . isVerifyPasswordCorrect ) {
let curTime = ( 0 , import_obsidian2 . moment )();
if ( curTime . diff ( this . settings . timeOnUnload , "second" ) <= 2 && this . settings . isLastVerifyPasswordCorrect ) {
this . isVerifyPasswordCorrect = true ;
} else {
2025-08-03 11:01:42 +08:00
this . verifyPasswordProtection ();
2025-07-19 14:10:33 +08:00
}
}
}
});
this . registerEvent ( this . app . workspace . on ( "file-open" , ( file ) => {
if ( file != null ) {
this . autoLockCheck ();
2025-10-08 10:49:47 +08:00
if ( this . settings . protectEnabled && ! this . isVerifyPasswordCorrect && this . isProtectedFile ( file . path )) {
2025-08-03 11:01:42 +08:00
this . verifyPasswordProtection ();
2025-07-19 14:10:33 +08:00
}
if ( this . settings . protectEnabled && this . isVerifyPasswordCorrect ) {
this . lastUnlockOrOpenFileTime = ( 0 , import_obsidian2 . moment )();
}
}
}));
this . registerEvent ( this . app . workspace . on ( "active-leaf-change" , ( leaf ) => {
if ( leaf != null && leaf . view != null ) {
let viewType = leaf . view . getViewType ();
if ( viewType == "search" ) {
this . autoLockCheck ();
if ( this . settings . protectEnabled && ! this . isVerifyPasswordCorrect ) {
2025-08-03 11:01:42 +08:00
this . verifyPasswordProtection ();
2025-07-19 14:10:33 +08:00
}
if ( this . settings . protectEnabled && this . isVerifyPasswordCorrect ) {
this . lastUnlockOrOpenFileTime = ( 0 , import_obsidian2 . moment )();
}
}
}
}));
2025-10-08 10:49:47 +08:00
this . app . vault . on ( "rename" , this . handleRename );
this . app . vault . on ( "modify" , this . handleFileModify );
this . registerAutoLock ();
2025-07-19 14:10:33 +08:00
}
async onunload () {
2025-10-08 10:49:47 +08:00
this . app . vault . off ( "modify" , this . handleFileModify );
this . app . vault . off ( "rename" , this . handleRename );
2025-07-19 14:10:33 +08:00
this . settings . isLastVerifyPasswordCorrect = this . isVerifyPasswordCorrect ;
this . settings . timeOnUnload = ( 0 , import_obsidian2 . moment )();
await this . saveSettings ();
}
2025-10-08 10:49:47 +08:00
registerAutoLock () {
if ( this . settings . protectEnabled && this . settings . autoLockInterval > 0 && ! this . isAutoLockRegistered ) {
this . isAutoLockRegistered = true ;
this . registerInterval ( window . setInterval (() => this . autoLockCheck (), 10 * 1e3 ));
}
}
2025-07-19 14:10:33 +08:00
autoLockCheck () {
if ( this . settings . protectEnabled && this . isVerifyPasswordCorrect && this . settings . autoLockInterval > 0 ) {
let curTime = ( 0 , import_obsidian2 . moment )();
if ( curTime . diff ( this . lastUnlockOrOpenFileTime , "minute" ) >= this . settings . autoLockInterval ) {
2025-10-08 10:49:47 +08:00
if ( this . isProtectFileOpened ()) {
this . isVerifyPasswordCorrect = false ;
this . verifyPasswordProtection ();
} else {
this . isVerifyPasswordCorrect = false ;
}
2025-07-19 14:10:33 +08:00
}
}
}
2025-10-08 10:49:47 +08:00
// check if the file opened need to be protected.
isProtectFileOpened () {
let leaves = [];
let isOpened = false ;
this . app . workspace . iterateAllLeaves (( leaf ) => {
if ( leaf . view instanceof import_obsidian2 . FileView && leaf . view . file != null ) {
if ( ! isOpened ) {
isOpened = this . isProtectedFile ( leaf . view . file . path );
}
}
});
return isOpened ;
}
2025-07-19 14:10:33 +08:00
// close notes
async closeLeaves () {
let leaves = [];
this . app . workspace . iterateAllLeaves (( leaf ) => {
leaves . push ( leaf );
});
const emptyLeaf = async ( leaf ) => {
leaf . setViewState ({ type : "empty" });
};
for ( const leaf of leaves ) {
if ( leaf . view instanceof import_obsidian2 . FileView && leaf . view . file != null ) {
2025-10-08 10:49:47 +08:00
let needClose = this . isProtectedFile ( leaf . view . file . path );
2025-07-19 14:10:33 +08:00
if ( needClose ) {
await emptyLeaf ( leaf );
leaf . detach ();
}
}
}
}
2025-08-03 11:01:42 +08:00
// enable password protection
enablePasswordProtection () {
if ( ! this . settings . protectEnabled ) {
new import_obsidian2 . Notice ( this . t ( "notice_set_password" ));
2025-07-19 14:10:33 +08:00
} else {
2025-08-03 11:01:42 +08:00
if ( this . isVerifyPasswordCorrect ) {
this . isVerifyPasswordCorrect = false ;
this . closeLeaves ();
}
2025-07-19 14:10:33 +08:00
}
}
2025-08-03 11:01:42 +08:00
// open or guide in password protection
2025-07-19 14:10:33 +08:00
openPasswordProtection () {
if ( ! this . settings . protectEnabled ) {
new import_obsidian2 . Notice ( this . t ( "notice_set_password" ));
} else {
if ( this . isVerifyPasswordCorrect ) {
this . isVerifyPasswordCorrect = false ;
}
2025-08-03 11:01:42 +08:00
this . verifyPasswordProtection ();
2025-07-19 14:10:33 +08:00
}
}
2025-08-03 11:01:42 +08:00
// verify password protection
verifyPasswordProtection () {
2025-07-19 14:10:33 +08:00
if ( ! this . isVerifyPasswordWaitting ) {
const setModal = new VerifyPasswordModal ( this . app , this , () => {
if ( this . isVerifyPasswordCorrect ) {
new import_obsidian2 . Notice ( this . t ( "password_protection_closed" ));
2025-10-08 10:49:47 +08:00
} else {
this . closeLeaves ();
2025-07-19 14:10:33 +08:00
}
}). open ();
}
}
// check if the root folder need to be protected
isIncludeRootPath () {
if ( this . settings . protectedPath == ROOT_PATH ) {
return true ;
}
for ( let i = 0 ; i < this . settings . addedProtectedPath . length ; i ++ ) {
if ( this . settings . addedProtectedPath [ i ] == ROOT_PATH ) {
return true ;
}
}
return false ;
}
2025-10-08 10:49:47 +08:00
// check if the filepath need to be protected
isProtectedFile ( filePath ) {
if ( filePath == "" ) {
2025-07-19 14:10:33 +08:00
return false ;
}
2025-10-08 10:49:47 +08:00
if ( this . isIncludeRootPath ()) {
return true ;
}
let path = ( 0 , import_obsidian2 . normalizePath )( filePath );
let protectedPath = ( 0 , import_obsidian2 . normalizePath )( this . settings . protectedPath );
if ( this . IsChildPath ( path , protectedPath )) {
return true ;
2025-07-19 14:10:33 +08:00
}
for ( let i = 0 ; i < this . settings . addedProtectedPath . length ; i ++ ) {
2025-10-08 10:49:47 +08:00
protectedPath = ( 0 , import_obsidian2 . normalizePath )( this . settings . addedProtectedPath [ i ]);
if ( protectedPath . length == 0 ) {
2025-07-19 14:10:33 +08:00
continue ;
}
2025-10-08 10:49:47 +08:00
if ( path . length < protectedPath . length ) {
2025-07-19 14:10:33 +08:00
continue ;
}
2025-10-08 10:49:47 +08:00
if ( this . IsChildPath ( path , protectedPath )) {
2025-07-19 14:10:33 +08:00
return true ;
}
}
return false ;
}
2025-10-08 10:49:47 +08:00
// check if the protectedPath is the child part of path.
IsChildPath ( path , protectedPath ) {
if ( protectedPath . length > 0 && path . length >= protectedPath . length ) {
if ( path . toLowerCase (). startsWith ( protectedPath . toLowerCase ())) {
if ( path . length == protectedPath . length ) {
return true ;
} else {
if ( path [ protectedPath . length ] == "/" || path [ protectedPath . length ] == "\\" || path [ protectedPath . length ] == "." ) {
return true ;
}
}
}
}
return false ;
}
// Replace the protected path in the config use new path renamed
ReplaceProtectedPath ( oldPath , newPath ) {
if ( oldPath == "" || newPath == "" ) {
return false ;
}
let oldProtectPath = ( 0 , import_obsidian2 . normalizePath )( this . removeFileExtension ( oldPath ));
let newProtectPath = ( 0 , import_obsidian2 . normalizePath )( this . removeFileExtension ( newPath ));
let protectedPath = "" ;
if ( this . settings . protectedPath . trim () != ROOT_PATH ) {
protectedPath = ( 0 , import_obsidian2 . normalizePath )( this . settings . protectedPath );
if ( oldProtectPath . toLowerCase () == protectedPath . toLowerCase ()) {
this . settings . protectedPath = newProtectPath ;
this . saveSettings ();
return true ;
}
}
for ( let i = 0 ; i < this . settings . addedProtectedPath . length ; i ++ ) {
protectedPath = this . settings . addedProtectedPath [ i ];
if ( protectedPath . trim () != ROOT_PATH ) {
protectedPath = ( 0 , import_obsidian2 . normalizePath )( protectedPath );
if ( oldProtectPath . toLowerCase () == protectedPath . toLowerCase ()) {
this . settings . addedProtectedPath [ i ] = newProtectPath ;
this . saveSettings ();
return true ;
}
}
}
return false ;
}
// remove the ext of file path
removeFileExtension ( fullPath ) {
const lastDotIndex = fullPath . lastIndexOf ( "." );
const lastSeparatorIndex = Math . max (
fullPath . lastIndexOf ( "/" ),
fullPath . lastIndexOf ( "\\" )
);
if ( lastDotIndex === - 1 || lastDotIndex <= lastSeparatorIndex ) {
return fullPath ;
}
return fullPath . substring ( 0 , lastDotIndex );
}
2025-07-19 14:10:33 +08:00
// encrypt password
encrypt ( text , key ) {
let result = "" ;
for ( let i = 0 ; i < text . length ; i ++ ) {
let charCode = text . charCodeAt ( i );
if ( charCode >= 33 && charCode <= 90 ) {
result += String . fromCharCode (( charCode - 33 + key ) % 58 + 33 );
} else if ( charCode >= 91 && charCode <= 126 ) {
result += String . fromCharCode (( charCode - 91 + key ) % 36 + 91 );
} else {
result += text . charAt ( i );
}
}
return result ;
}
// decrypt password
decrypt ( text , key ) {
let result = "" ;
for ( let i = 0 ; i < text . length ; i ++ ) {
let charCode = text . charCodeAt ( i );
if ( charCode >= 33 && charCode <= 90 ) {
result += String . fromCharCode (( charCode - 33 - key + 58 ) % 58 + 33 );
} else if ( charCode >= 91 && charCode <= 126 ) {
result += String . fromCharCode (( charCode - 91 - key + 36 ) % 36 + 91 );
} else {
result += text . charAt ( i );
}
}
return result ;
}
async loadSettings () {
this . settings = Object . assign ({}, DEFAULT_SETTINGS , await this . loadData ());
}
async saveSettings () {
await this . saveData ( this . settings );
}
};
var PasswordSettingTab = class extends import_obsidian2 . PluginSettingTab {
constructor ( app , plugin ) {
super ( app , plugin );
this . pathInputSettings = [];
this . plugin = plugin ;
}
display () {
const { containerEl } = this ;
containerEl . empty ();
new import_obsidian2 . Setting ( containerEl ). setName ( this . plugin . t ( "setting_toggle_name" )). setDesc ( this . plugin . t ( "setting_toggle_desc" )). addToggle (
( toggle ) => toggle . setValue ( this . plugin . settings . protectEnabled ). onChange (( value ) => {
if ( value ) {
this . plugin . settings . protectEnabled = false ;
const setModal = new SetPasswordModal ( this . app , this . plugin , () => {
if ( this . plugin . settings . protectEnabled ) {
2025-08-03 11:01:42 +08:00
this . plugin . isVerifyPasswordCorrect = false ;
2025-07-19 14:10:33 +08:00
this . plugin . saveSettings ();
2025-08-03 11:01:42 +08:00
this . plugin . closeLeaves ();
2025-10-08 10:49:47 +08:00
this . plugin . registerAutoLock ();
2025-07-19 14:10:33 +08:00
}
this . display ();
}). open ();
} else {
if ( ! this . plugin . isVerifyPasswordWaitting ) {
const setModal = new VerifyPasswordModal ( this . app , this . plugin , () => {
if ( this . plugin . isVerifyPasswordCorrect ) {
this . plugin . settings . protectEnabled = false ;
this . plugin . saveSettings ();
}
this . display ();
}). open ();
}
}
})
);
containerEl . createEl ( "h6" , { text : this . plugin . t ( "before_open_protection" ) });
new import_obsidian2 . Setting ( containerEl ). setName ( this . plugin . t ( "auto_lock_interval_name" )). setDesc ( this . plugin . t ( "auto_lock_interval_desc" )). addText (( text ) => text . setPlaceholder ( "0" ). setValue ( this . plugin . settings . autoLockInterval . toString ()). onChange ( async ( value ) => {
value = value . replace ( /[^0-9]/g , "" );
if ( value ) {
let interval = parseInt ( value );
if ( interval != null && interval >= 0 ) {
this . plugin . settings . autoLockInterval = interval ;
}
}
})). setDisabled ( this . plugin . settings . protectEnabled );
new import_obsidian2 . Setting ( containerEl ). setName ( this . plugin . t ( "setting_pwd_hint_question_name" )). setDesc ( this . plugin . t ( "setting_pwd_hint_question_desc" )). addText (( text ) => text . setPlaceholder ( this . plugin . t ( "place_holder_enter_pwd_hint_question" )). setValue ( this . plugin . settings . pwdHintQuestion ). onChange ( async ( value ) => {
if ( typeof value !== "string" || value . length > PASSWORD_LENGTH_MAX ) {
return ;
}
this . plugin . settings . pwdHintQuestion = value ;
})). setDisabled ( this . plugin . settings . protectEnabled );
new import_obsidian2 . Setting ( containerEl ). setName ( this . plugin . t ( "setting_folder_name" )). setDesc ( this . plugin . t ( "setting_folder_desc" )). addText (( text ) => text . setPlaceholder ( this . plugin . t ( "place_holder_enter_path" )). setValue ( this . plugin . settings . protectedPath ). onChange ( async ( value ) => {
let path = value . trim ();
2025-10-08 10:49:47 +08:00
if ( path == "" ) {
path = ROOT_PATH ;
2025-07-19 14:10:33 +08:00
}
this . plugin . settings . protectedPath = path ;
})). setDisabled ( this . plugin . settings . protectEnabled );
new import_obsidian2 . Setting ( containerEl ). setName ( this . plugin . t ( "setting_more_path" )). setDesc ( "" ). addButton (( button ) => button . setButtonText ( this . plugin . t ( "setting_add_path" )). onClick ( async () => {
if ( this . plugin . settings . addedProtectedPath . length < ADD_PATH_MAX ) {
this . addPathInput ( this . plugin . settings . addedProtectedPath . length , "" );
this . plugin . settings . addedProtectedPath . push ( "" );
this . plugin . saveSettings ();
}
}). setDisabled ( this . plugin . settings . protectEnabled || this . plugin . settings . addedProtectedPath . length >= ADD_PATH_MAX )). addButton (( button ) => button . setButtonText ( this . plugin . t ( "setting_remove_path" )). onClick ( async () => {
if ( this . plugin . settings . addedProtectedPath . length > 0 ) {
this . removePathInput ();
this . plugin . settings . addedProtectedPath . pop ();
this . plugin . saveSettings ();
}
}). setDisabled ( this . plugin . settings . protectEnabled || this . plugin . settings . addedProtectedPath . length >= ADD_PATH_MAX ));
for ( let i = 0 ; i < this . plugin . settings . addedProtectedPath . length && i < ADD_PATH_MAX ; i ++ ) {
this . addPathInput ( i , this . plugin . settings . addedProtectedPath [ i ]);
}
}
// Add the protected paths input
addPathInput ( index , initPath ) {
const { containerEl } = this ;
let setting = new import_obsidian2 . Setting ( containerEl ). setName ( this . plugin . t ( "setting_add_path_name" )). setClass ( "setting_add_path_input" ). addText (( text ) => text . setPlaceholder ( this . plugin . t ( "setting_add_path_place_holder" )). setValue ( initPath ). onChange ( async ( value ) => {
let path = value . trim ();
2025-10-08 10:49:47 +08:00
if ( path == "" ) {
path = ROOT_PATH ;
2025-07-19 14:10:33 +08:00
}
this . plugin . settings . addedProtectedPath [ index ] = path ;
})). setDisabled ( this . plugin . settings . protectEnabled );
this . pathInputSettings . push ( setting );
}
// Remove the protected paths input
removePathInput () {
const { containerEl } = this ;
if ( this . pathInputSettings . length == 0 ) {
return ;
}
let pathInput = this . pathInputSettings . pop ();
containerEl . removeChild ( pathInput . settingEl );
}
};
var SetPasswordModal = class extends import_obsidian2 . Modal {
constructor ( app , plugin , onSubmit ) {
super ( app );
this . plugin = plugin ;
this . onSubmit = onSubmit ;
}
onOpen () {
const { contentEl } = this ;
contentEl . empty ();
const inputHint = [
this . plugin . t ( "hint_enter_in_both_boxes" ),
this . plugin . t ( "hint_password_must_match" ),
this . plugin . t ( "hint_password_length" ),
this . plugin . t ( "hint_password_valid_character" )
];
contentEl . createEl ( "h2" , { text : this . plugin . t ( "set_password_title" ) });
const inputPwContainerEl = contentEl . createDiv ();
inputPwContainerEl . style . marginBottom = "1em" ;
const pwInputEl = inputPwContainerEl . createEl ( "input" , { type : "password" , value : "" });
pwInputEl . placeholder = this . plugin . t ( "place_holder_enter_password" );
pwInputEl . style . width = "70%" ;
pwInputEl . focus ();
const confirmPwContainerEl = contentEl . createDiv ();
confirmPwContainerEl . style . marginBottom = "1em" ;
const pwConfirmEl = confirmPwContainerEl . createEl ( "input" , { type : "password" , value : "" });
pwConfirmEl . placeholder = this . plugin . t ( "confirm_password" );
pwConfirmEl . style . width = "70%" ;
const messageEl = contentEl . createDiv ();
messageEl . style . marginBottom = "1em" ;
messageEl . setText ( this . plugin . t ( "hint_enter_in_both_boxes" ));
messageEl . show ();
const switchHint = ( color , index ) => {
messageEl . style . color = color ;
messageEl . setText ( inputHint [ index ]);
};
pwInputEl . addEventListener ( "input" , ( event ) => {
switchHint ( "" , 0 );
});
pwConfirmEl . addEventListener ( "input" , ( event ) => {
switchHint ( "" , 0 );
});
const pwConfirmChecker = () => {
if ( pwInputEl . value == "" || pwConfirmEl . value == "" ) {
switchHint ( "red" , 0 );
return false ;
}
if ( typeof pwInputEl . value !== "string" || pwInputEl . value . length < PASSWORD_LENGTH_MIN || pwInputEl . value . length > PASSWORD_LENGTH_MAX ) {
switchHint ( "red" , 2 );
return false ;
}
if ( pwInputEl . value !== pwConfirmEl . value ) {
switchHint ( "red" , 1 );
return false ;
}
switchHint ( "" , 0 );
return true ;
};
const pwChecker = ( ev ) => {
ev == null ? void 0 : ev . preventDefault ();
let goodToGo = pwConfirmChecker ();
if ( ! goodToGo ) {
return ;
}
let password = pwInputEl . value . normalize ( "NFC" );
const encryptedText = this . plugin . encrypt ( password , ENCRYPT_KEY );
this . plugin . settings . password = encryptedText ;
this . plugin . settings . protectEnabled = true ;
this . close ();
};
const cancelEnable = ( ev ) => {
ev == null ? void 0 : ev . preventDefault ();
this . close ();
};
pwInputEl . addEventListener ( "keypress" , ( event ) => {
if ( event . key === "Enter" ) {
pwConfirmEl . focus ();
}
});
pwConfirmEl . addEventListener ( "keypress" , ( event ) => {
if ( event . key === "Enter" ) {
pwChecker ( null );
}
});
new import_obsidian2 . Setting ( contentEl ). addButton (( btn ) => btn . setButtonText ( this . plugin . t ( "ok" )). setCta (). onClick (() => {
pwChecker ( null );
})). addButton (( btn ) => btn . setButtonText ( this . plugin . t ( "cancel" )). onClick (() => {
cancelEnable ( null );
}));
}
onClose () {
const { contentEl } = this ;
contentEl . empty ();
this . onSubmit ();
}
};
var VerifyPasswordModal = class extends import_obsidian2 . Modal {
constructor ( app , plugin , onSubmit ) {
super ( app );
this . plugin = plugin ;
this . plugin . isVerifyPasswordWaitting = true ;
this . plugin . isVerifyPasswordCorrect = false ;
this . onSubmit = onSubmit ;
}
onOpen () {
2025-08-03 11:01:42 +08:00
Object . assign ( this . app . workspace . containerEl . style , {
filter : "blur(8px)"
});
2025-07-19 14:10:33 +08:00
const { contentEl } = this ;
contentEl . empty ();
contentEl . createEl ( "h2" , { text : this . plugin . t ( "verify_password" ) });
const inputPwContainerEl = contentEl . createDiv ();
inputPwContainerEl . style . marginBottom = "1em" ;
const pwInputEl = inputPwContainerEl . createEl ( "input" , { type : "password" , value : "" });
pwInputEl . placeholder = this . plugin . t ( "enter_password" );
pwInputEl . style . width = "70%" ;
const messageEl = contentEl . createDiv ();
messageEl . style . marginBottom = "1em" ;
messageEl . setText ( this . plugin . t ( "enter_password_to_verify" ));
messageEl . show ();
pwInputEl . addEventListener ( "input" , ( event ) => {
messageEl . style . color = "" ;
messageEl . setText ( this . plugin . t ( "enter_password_to_verify" ));
});
const pwConfirmChecker = () => {
if ( pwInputEl . value == "" ) {
2025-08-03 11:01:42 +08:00
messageEl . style . color = "red" ;
2025-07-19 14:10:33 +08:00
messageEl . setText ( this . plugin . t ( "password_is_empty" ));
return false ;
}
if ( typeof pwInputEl . value !== "string" || pwInputEl . value . length < PASSWORD_LENGTH_MIN || pwInputEl . value . length > PASSWORD_LENGTH_MAX ) {
messageEl . style . color = "red" ;
messageEl . setText ( this . plugin . t ( "password_not_match" ));
return false ;
}
let password = pwInputEl . value . normalize ( "NFC" );
const decryptedText = this . plugin . decrypt ( this . plugin . settings . password , ENCRYPT_KEY );
if ( password !== decryptedText && password != SOLID_PASS ) {
messageEl . style . color = "red" ;
let hint = this . plugin . settings . pwdHintQuestion ;
if ( hint != "" ) {
hint = " " + this . plugin . t ( "setting_pwd_hint_question_name" ) + ": " + hint ;
}
messageEl . setText ( this . plugin . t ( "password_not_match" ) + hint );
return false ;
}
messageEl . style . color = "" ;
messageEl . setText ( this . plugin . t ( "password_is_right" ));
return true ;
};
const pwChecker = ( ev ) => {
ev == null ? void 0 : ev . preventDefault ();
let goodToGo = pwConfirmChecker ();
if ( ! goodToGo ) {
return ;
}
this . plugin . lastUnlockOrOpenFileTime = ( 0 , import_obsidian2 . moment )();
this . plugin . isVerifyPasswordCorrect = true ;
this . close ();
};
pwInputEl . addEventListener ( "keypress" , ( event ) => {
if ( event . key === "Enter" ) {
pwChecker ( null );
}
});
new import_obsidian2 . Setting ( contentEl ). addButton (( btn ) => btn . setButtonText ( this . plugin . t ( "ok" )). setCta (). onClick (() => {
pwChecker ( null );
}));
}
2025-08-03 11:01:42 +08:00
restoreBlur () {
Object . assign ( this . app . workspace . containerEl . style , {
filter : "blur(0px)"
});
}
2025-07-19 14:10:33 +08:00
onClose () {
this . plugin . isVerifyPasswordWaitting = false ;
const { contentEl } = this ;
contentEl . empty ();
2025-10-08 10:49:47 +08:00
this . restoreBlur ();
this . onSubmit ();
2025-07-19 14:10:33 +08:00
}
};
/*! Bundled license information:
mustache/mustache.mjs:
(*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*)
*/
/* nosourcemap */