Experimental-user-scripts-support.patch 390 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Fri, 13 Aug 2021 17:10:47 +0000
  3. Subject: Experimental user scripts support
  4. Activate the user scripts functionality for Android,
  5. as it is available in the Desktop version.
  6. It is possible to add user scripts in two ways: by
  7. selecting files from the picker in the settings or
  8. downloading the scripts and opening them from downloads
  9. (only if such files end with '.user.js').
  10. New imported scripts are disabled by default: they
  11. can be activated via the UI.
  12. Parsed user script headers are: name, version, description,
  13. include, exclude, match, exclude_match (only http and
  14. https), run-at (document-start, document-end,
  15. document-idle), homepage, url_source
  16. The UI also allows you to see the source of the script.
  17. See also: components/user_scripts/README.md
  18. Requires patch: Adds-support-for-writing-URIs.patch
  19. Original License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html
  20. License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
  21. ---
  22. chrome/android/BUILD.gn | 5 +
  23. .../android/java/res/xml/main_preferences.xml | 5 +
  24. .../browser/download/DownloadUtils.java | 6 +
  25. .../init/ProcessInitializationHandler.java | 3 +
  26. chrome/android/java_sources.gni | 3 +
  27. chrome/browser/BUILD.gn | 5 +
  28. chrome/browser/about_flags.cc | 5 +
  29. .../browser/chrome_content_browser_client.cc | 3 +-
  30. chrome/browser/flag_descriptions.cc | 5 +
  31. chrome/browser/flag_descriptions.h | 3 +
  32. chrome/browser/prefs/browser_prefs.cc | 2 +
  33. chrome/browser/profiles/BUILD.gn | 1 +
  34. ...hrome_browser_main_extra_parts_profiles.cc | 3 +
  35. chrome/browser/profiles/profile_manager.cc | 9 +
  36. chrome/browser/profiles/renderer_updater.cc | 10 +-
  37. chrome/browser/profiles/renderer_updater.h | 1 +
  38. .../webui/chrome_web_ui_controller_factory.cc | 3 +
  39. chrome/chrome_paks.gni | 2 +
  40. chrome/common/renderer_configuration.mojom | 1 +
  41. chrome/renderer/BUILD.gn | 1 +
  42. .../chrome_content_renderer_client.cc | 37 +
  43. .../renderer/chrome_render_thread_observer.cc | 3 +
  44. components/components_strings.grd | 1 +
  45. components/user_scripts/README.md | 150 ++++
  46. components/user_scripts/android/BUILD.gn | 83 ++
  47. .../java/res/layout/accept_script_item.xml | 160 ++++
  48. .../java/res/layout/accept_script_list.xml | 10 +
  49. .../java/res/layout/scripts_preference.xml | 40 +
  50. .../android/java/res/values/dimens.xml | 11 +
  51. .../java/res/xml/userscripts_preferences.xml | 34 +
  52. .../user_scripts/UserScriptsUtils.java | 87 ++
  53. .../user_scripts/FragmentWindowAndroid.java | 90 ++
  54. .../user_scripts/IUserScriptsUtils.java | 22 +
  55. .../components/user_scripts/ScriptInfo.java | 37 +
  56. .../user_scripts/ScriptListBaseAdapter.java | 163 ++++
  57. .../user_scripts/ScriptListPreference.java | 171 ++++
  58. .../user_scripts/UserScriptsBridge.java | 212 +++++
  59. .../user_scripts/UserScriptsPreferences.java | 116 +++
  60. .../user_scripts/android/java_sources.gni | 18 +
  61. .../android/user_scripts_bridge.cc | 173 ++++
  62. .../android/user_scripts_bridge.h | 31 +
  63. components/user_scripts/browser/BUILD.gn | 81 ++
  64. .../user_scripts/browser/file_task_runner.cc | 40 +
  65. .../user_scripts/browser/file_task_runner.h | 34 +
  66. .../browser/resources/browser_resources.grd | 14 +
  67. .../browser/resources/user-script-ui/BUILD.gn | 12 +
  68. .../user-script-ui/user-scripts-ui.html | 14 +
  69. .../user-script-ui/user-scripts-ui.js | 9 +
  70. .../browser/ui/user_scripts_ui.cc | 147 ++++
  71. .../user_scripts/browser/ui/user_scripts_ui.h | 37 +
  72. .../browser/user_script_loader.cc | 716 ++++++++++++++++
  73. .../user_scripts/browser/user_script_loader.h | 169 ++++
  74. .../browser/user_script_pref_info.cc | 34 +
  75. .../browser/user_script_pref_info.h | 72 ++
  76. .../user_scripts/browser/user_script_prefs.cc | 278 ++++++
  77. .../user_scripts/browser/user_script_prefs.h | 62 ++
  78. .../browser/userscripts_browser_client.cc | 78 ++
  79. .../browser/userscripts_browser_client.h | 62 ++
  80. components/user_scripts/common/BUILD.gn | 49 ++
  81. components/user_scripts/common/constants.h | 21 +
  82. components/user_scripts/common/error_utils.cc | 54 ++
  83. components/user_scripts/common/error_utils.h | 24 +
  84. .../common/extension_message_generator.cc | 29 +
  85. .../common/extension_message_generator.h | 11 +
  86. .../user_scripts/common/extension_messages.cc | 40 +
  87. .../user_scripts/common/extension_messages.h | 70 ++
  88. components/user_scripts/common/host_id.cc | 31 +
  89. components/user_scripts/common/host_id.h | 35 +
  90. .../user_scripts/common/script_constants.h | 33 +
  91. components/user_scripts/common/url_pattern.cc | 803 ++++++++++++++++++
  92. components/user_scripts/common/url_pattern.h | 302 +++++++
  93. .../user_scripts/common/url_pattern_set.cc | 335 ++++++++
  94. .../user_scripts/common/url_pattern_set.h | 160 ++++
  95. components/user_scripts/common/user_script.cc | 329 +++++++
  96. components/user_scripts/common/user_script.h | 403 +++++++++
  97. .../common/user_scripts_features.cc | 32 +
  98. .../common/user_scripts_features.h | 34 +
  99. components/user_scripts/common/view_type.cc | 39 +
  100. components/user_scripts/common/view_type.h | 48 ++
  101. components/user_scripts/renderer/BUILD.gn | 67 ++
  102. .../renderer/extension_frame_helper.cc | 96 +++
  103. .../renderer/extension_frame_helper.h | 91 ++
  104. .../user_scripts/renderer/injection_host.cc | 12 +
  105. .../user_scripts/renderer/injection_host.h | 41 +
  106. .../renderer/resources/greasemonkey_api.js | 82 ++
  107. .../user_scripts_renderer_resources.grd | 14 +
  108. .../user_scripts/renderer/script_context.cc | 215 +++++
  109. .../user_scripts/renderer/script_context.h | 69 ++
  110. .../user_scripts/renderer/script_injection.cc | 343 ++++++++
  111. .../user_scripts/renderer/script_injection.h | 154 ++++
  112. .../renderer/script_injection_callback.cc | 25 +
  113. .../renderer/script_injection_callback.h | 38 +
  114. .../renderer/script_injection_manager.cc | 417 +++++++++
  115. .../renderer/script_injection_manager.h | 101 +++
  116. .../user_scripts/renderer/script_injector.h | 96 +++
  117. .../user_scripts/renderer/scripts_run_info.cc | 31 +
  118. .../user_scripts/renderer/scripts_run_info.h | 69 ++
  119. .../renderer/user_script_injector.cc | 228 +++++
  120. .../renderer/user_script_injector.h | 86 ++
  121. .../user_scripts/renderer/user_script_set.cc | 262 ++++++
  122. .../user_scripts/renderer/user_script_set.h | 101 +++
  123. .../renderer/user_script_set_manager.cc | 77 ++
  124. .../renderer/user_script_set_manager.h | 61 ++
  125. .../renderer/user_scripts_dispatcher.cc | 36 +
  126. .../renderer/user_scripts_dispatcher.h | 49 ++
  127. .../renderer/user_scripts_renderer_client.cc | 105 +++
  128. .../renderer/user_scripts_renderer_client.h | 37 +
  129. .../renderer/web_ui_injection_host.cc | 40 +
  130. .../renderer/web_ui_injection_host.h | 27 +
  131. .../strings/userscripts_strings.grdp | 57 ++
  132. tools/gritsettings/resource_ids.spec | 6 +
  133. 111 files changed, 9597 insertions(+), 2 deletions(-)
  134. create mode 100644 components/user_scripts/README.md
  135. create mode 100755 components/user_scripts/android/BUILD.gn
  136. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_item.xml
  137. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_list.xml
  138. create mode 100644 components/user_scripts/android/java/res/layout/scripts_preference.xml
  139. create mode 100755 components/user_scripts/android/java/res/values/dimens.xml
  140. create mode 100644 components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  141. create mode 100755 components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  142. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  143. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  144. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  145. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  146. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  147. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  148. create mode 100755 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  149. create mode 100644 components/user_scripts/android/java_sources.gni
  150. create mode 100644 components/user_scripts/android/user_scripts_bridge.cc
  151. create mode 100644 components/user_scripts/android/user_scripts_bridge.h
  152. create mode 100755 components/user_scripts/browser/BUILD.gn
  153. create mode 100755 components/user_scripts/browser/file_task_runner.cc
  154. create mode 100755 components/user_scripts/browser/file_task_runner.h
  155. create mode 100644 components/user_scripts/browser/resources/browser_resources.grd
  156. create mode 100644 components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  157. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  158. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  159. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.cc
  160. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.h
  161. create mode 100755 components/user_scripts/browser/user_script_loader.cc
  162. create mode 100755 components/user_scripts/browser/user_script_loader.h
  163. create mode 100644 components/user_scripts/browser/user_script_pref_info.cc
  164. create mode 100644 components/user_scripts/browser/user_script_pref_info.h
  165. create mode 100644 components/user_scripts/browser/user_script_prefs.cc
  166. create mode 100644 components/user_scripts/browser/user_script_prefs.h
  167. create mode 100755 components/user_scripts/browser/userscripts_browser_client.cc
  168. create mode 100755 components/user_scripts/browser/userscripts_browser_client.h
  169. create mode 100755 components/user_scripts/common/BUILD.gn
  170. create mode 100755 components/user_scripts/common/constants.h
  171. create mode 100755 components/user_scripts/common/error_utils.cc
  172. create mode 100755 components/user_scripts/common/error_utils.h
  173. create mode 100755 components/user_scripts/common/extension_message_generator.cc
  174. create mode 100755 components/user_scripts/common/extension_message_generator.h
  175. create mode 100755 components/user_scripts/common/extension_messages.cc
  176. create mode 100755 components/user_scripts/common/extension_messages.h
  177. create mode 100755 components/user_scripts/common/host_id.cc
  178. create mode 100755 components/user_scripts/common/host_id.h
  179. create mode 100755 components/user_scripts/common/script_constants.h
  180. create mode 100755 components/user_scripts/common/url_pattern.cc
  181. create mode 100755 components/user_scripts/common/url_pattern.h
  182. create mode 100755 components/user_scripts/common/url_pattern_set.cc
  183. create mode 100755 components/user_scripts/common/url_pattern_set.h
  184. create mode 100755 components/user_scripts/common/user_script.cc
  185. create mode 100755 components/user_scripts/common/user_script.h
  186. create mode 100644 components/user_scripts/common/user_scripts_features.cc
  187. create mode 100644 components/user_scripts/common/user_scripts_features.h
  188. create mode 100755 components/user_scripts/common/view_type.cc
  189. create mode 100755 components/user_scripts/common/view_type.h
  190. create mode 100755 components/user_scripts/renderer/BUILD.gn
  191. create mode 100755 components/user_scripts/renderer/extension_frame_helper.cc
  192. create mode 100755 components/user_scripts/renderer/extension_frame_helper.h
  193. create mode 100755 components/user_scripts/renderer/injection_host.cc
  194. create mode 100755 components/user_scripts/renderer/injection_host.h
  195. create mode 100755 components/user_scripts/renderer/resources/greasemonkey_api.js
  196. create mode 100755 components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  197. create mode 100755 components/user_scripts/renderer/script_context.cc
  198. create mode 100755 components/user_scripts/renderer/script_context.h
  199. create mode 100755 components/user_scripts/renderer/script_injection.cc
  200. create mode 100755 components/user_scripts/renderer/script_injection.h
  201. create mode 100755 components/user_scripts/renderer/script_injection_callback.cc
  202. create mode 100755 components/user_scripts/renderer/script_injection_callback.h
  203. create mode 100755 components/user_scripts/renderer/script_injection_manager.cc
  204. create mode 100755 components/user_scripts/renderer/script_injection_manager.h
  205. create mode 100755 components/user_scripts/renderer/script_injector.h
  206. create mode 100755 components/user_scripts/renderer/scripts_run_info.cc
  207. create mode 100755 components/user_scripts/renderer/scripts_run_info.h
  208. create mode 100755 components/user_scripts/renderer/user_script_injector.cc
  209. create mode 100755 components/user_scripts/renderer/user_script_injector.h
  210. create mode 100755 components/user_scripts/renderer/user_script_set.cc
  211. create mode 100755 components/user_scripts/renderer/user_script_set.h
  212. create mode 100755 components/user_scripts/renderer/user_script_set_manager.cc
  213. create mode 100755 components/user_scripts/renderer/user_script_set_manager.h
  214. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.cc
  215. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.h
  216. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.cc
  217. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.h
  218. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.cc
  219. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.h
  220. create mode 100755 components/user_scripts/strings/userscripts_strings.grdp
  221. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  222. --- a/chrome/android/BUILD.gn
  223. +++ b/chrome/android/BUILD.gn
  224. @@ -265,6 +265,10 @@ android_resources("chrome_app_java_resources") {
  225. "//third_party/androidx:androidx_gridlayout_gridlayout_java",
  226. "//third_party/androidx:androidx_preference_preference_java",
  227. ]
  228. +
  229. + # this need to be into android_resources("chrome_app_java_resources") section because
  230. + # android:java_resources are packed *_percent.pak and placed in the executable folder
  231. + deps += [ "//components/user_scripts/android:java_resources" ]
  232. }
  233. if (enable_vr) {
  234. @@ -563,6 +567,7 @@ android_library("chrome_java") {
  235. "//components/ukm/android:java",
  236. "//components/url_formatter/android:url_formatter_java",
  237. "//components/user_prefs/android:java",
  238. + "//components/user_scripts/android:java",
  239. "//components/variations:variations_java",
  240. "//components/variations/android:variations_java",
  241. "//components/version_info/android:version_constants_java",
  242. diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
  243. --- a/chrome/android/java/res/xml/main_preferences.xml
  244. +++ b/chrome/android/java/res/xml/main_preferences.xml
  245. @@ -86,6 +86,11 @@
  246. android:key="useragent_settings"
  247. android:order="20"
  248. android:title="@string/prefs_useragent_settings"/>
  249. + <Preference
  250. + android:fragment="org.chromium.components.user_scripts.UserScriptsPreferences"
  251. + android:key="userscripts_settings"
  252. + android:order="20"
  253. + android:title="@string/prefs_userscripts_settings"/>
  254. <Preference
  255. android:fragment="org.chromium.chrome.browser.language.settings.LanguageSettings"
  256. android:key="languages"
  257. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  258. --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  259. +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  260. @@ -70,6 +70,7 @@ import org.chromium.content_public.browser.BrowserStartupController;
  261. import org.chromium.content_public.browser.LoadUrlParams;
  262. import org.chromium.ui.base.DeviceFormFactor;
  263. import org.chromium.ui.widget.Toast;
  264. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  265. import java.io.File;
  266. @@ -417,6 +418,11 @@ public class DownloadUtils {
  267. public static boolean openFile(String filePath, String mimeType, String downloadGuid,
  268. OTRProfileID otrProfileID, String originalUrl, String referrer,
  269. @DownloadOpenSource int source, Context context) {
  270. + if (UserScriptsUtils.getInstance().openFile(filePath, mimeType, downloadGuid,
  271. + originalUrl, referrer,
  272. + getUriForItem(filePath))) {
  273. + return true;
  274. + }
  275. DownloadMetrics.recordDownloadOpen(source, mimeType);
  276. DownloadManagerService service = DownloadManagerService.getDownloadManagerService();
  277. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  278. --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  279. +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  280. @@ -122,6 +122,8 @@ import java.util.Date;
  281. import java.util.List;
  282. import java.util.Locale;
  283. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  284. +
  285. /**
  286. * Handles the initialization dependences of the browser process. This is meant to handle the
  287. * initialization that is not tied to any particular Activity, and the logic that should only be
  288. @@ -311,6 +313,7 @@ public class ProcessInitializationHandler {
  289. DefaultBrowserInfo.initBrowserFetcher();
  290. + UserScriptsUtils.Initialize();
  291. AfterStartupTaskUtils.setStartupComplete();
  292. PartnerBrowserCustomizations.getInstance().setOnInitializeAsyncFinished(
  293. diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
  294. --- a/chrome/android/java_sources.gni
  295. +++ b/chrome/android/java_sources.gni
  296. @@ -20,6 +20,7 @@ import("//chrome/common/features.gni")
  297. import("//components/feed/features.gni")
  298. import("//components/offline_pages/buildflags/features.gni")
  299. import("//device/vr/buildflags/buildflags.gni")
  300. +import("//components/user_scripts/android/java_sources.gni")
  301. chrome_java_sources += public_autofill_assistant_java_sources
  302. @@ -56,3 +57,5 @@ if (enable_arcore) {
  303. "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java",
  304. ]
  305. }
  306. +
  307. +chrome_java_sources += userscripts_java_sources
  308. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  309. --- a/chrome/browser/BUILD.gn
  310. +++ b/chrome/browser/BUILD.gn
  311. @@ -3417,6 +3417,11 @@ static_library("browser") {
  312. ]
  313. deps += [ "//chrome/android/modules/dev_ui/provider:native" ]
  314. }
  315. + deps += [
  316. + "//components/user_scripts/common",
  317. + "//components/user_scripts/browser",
  318. + "//components/user_scripts/android",
  319. + ]
  320. } else {
  321. #!is_android
  322. sources += [
  323. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
  324. --- a/chrome/browser/about_flags.cc
  325. +++ b/chrome/browser/about_flags.cc
  326. @@ -148,6 +148,7 @@
  327. #include "components/translate/core/browser/translate_ranker_impl.h"
  328. #include "components/translate/core/common/translate_util.h"
  329. #include "components/ui_devtools/switches.h"
  330. +#include "components/user_scripts/common/user_scripts_features.h"
  331. #include "components/version_info/version_info.h"
  332. #include "components/viz/common/features.h"
  333. #include "components/viz/common/switches.h"
  334. @@ -7149,6 +7150,10 @@ const FeatureEntry kFeatureEntries[] = {
  335. chromeos::features::kClipboardHistoryNudgeSessionReset)},
  336. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  337. + {"enable-userscripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  338. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  339. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  340. +
  341. #if BUILDFLAG(IS_WIN)
  342. {"enable-media-foundation-video-capture",
  343. flag_descriptions::kEnableMediaFoundationVideoCaptureName,
  344. diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
  345. --- a/chrome/browser/chrome_content_browser_client.cc
  346. +++ b/chrome/browser/chrome_content_browser_client.cc
  347. @@ -4793,7 +4793,8 @@ ChromeContentBrowserClient::CreateURLLoaderThrottles(
  348. chrome::mojom::DynamicParams dynamic_params = {
  349. profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch),
  350. profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict),
  351. - profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)};
  352. + profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps),
  353. + false /*-> allow_userscript, don't care */};
  354. result.push_back(std::make_unique<GoogleURLLoaderThrottle>(
  355. #if BUILDFLAG(IS_ANDROID)
  356. client_data_header, is_tab_large_enough,
  357. diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
  358. --- a/chrome/browser/flag_descriptions.cc
  359. +++ b/chrome/browser/flag_descriptions.cc
  360. @@ -5957,6 +5957,11 @@ const char kQuickCommandsDescription[] =
  361. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
  362. // BUILDFLAG(IS_FUCHSIA)
  363. +const char kEnableLoggingUserScriptsName[] = "Enable logging user scripts component";
  364. +const char kEnableLoggingUserScriptsDescription[] =
  365. + "Enables logging for troubleshooting feature. "
  366. + "Enabling logs may make browsing slower.";
  367. +
  368. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  369. const char kWebShareName[] = "Web Share";
  370. const char kWebShareDescription[] =
  371. diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
  372. --- a/chrome/browser/flag_descriptions.h
  373. +++ b/chrome/browser/flag_descriptions.h
  374. @@ -3430,6 +3430,9 @@ extern const char kQuickCommandsDescription[];
  375. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
  376. // defined (OS_FUCHSIA)
  377. +extern const char kEnableLoggingUserScriptsName[];
  378. +extern const char kEnableLoggingUserScriptsDescription[];
  379. +
  380. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  381. extern const char kWebShareName[];
  382. extern const char kWebShareDescription[];
  383. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  384. --- a/chrome/browser/prefs/browser_prefs.cc
  385. +++ b/chrome/browser/prefs/browser_prefs.cc
  386. @@ -246,6 +246,7 @@
  387. #include "components/ntp_tiles/popular_sites_impl.h"
  388. #include "components/permissions/contexts/geolocation_permission_context_android.h"
  389. #include "components/query_tiles/tile_service_prefs.h"
  390. +#include "components/user_scripts/browser/user_script_prefs.h"
  391. #else // BUILDFLAG(IS_ANDROID)
  392. #include "chrome/browser/autofill_assistant/password_change/apc_client.h"
  393. #include "chrome/browser/cart/cart_service.h"
  394. @@ -1335,6 +1336,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
  395. translate::TranslatePrefs::RegisterProfilePrefs(registry);
  396. omnibox::RegisterProfilePrefs(registry);
  397. ZeroSuggestProvider::RegisterProfilePrefs(registry);
  398. + user_scripts::UserScriptsPrefs::RegisterProfilePrefs(registry);
  399. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  400. RegisterSessionServiceLogProfilePrefs(registry);
  401. diff --git a/chrome/browser/profiles/BUILD.gn b/chrome/browser/profiles/BUILD.gn
  402. --- a/chrome/browser/profiles/BUILD.gn
  403. +++ b/chrome/browser/profiles/BUILD.gn
  404. @@ -44,6 +44,7 @@ source_set("profile") {
  405. "//components/profile_metrics",
  406. "//components/sync/driver",
  407. "//components/variations",
  408. + "//components/user_scripts/browser",
  409. "//content/public/browser",
  410. "//extensions/buildflags",
  411. ]
  412. diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  413. --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  414. +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  415. @@ -244,6 +244,8 @@
  416. #include "chrome/browser/ui/cocoa/screentime/screentime_features.h"
  417. #endif
  418. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  419. +
  420. namespace chrome {
  421. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  422. @@ -582,6 +584,7 @@ void ChromeBrowserMainExtraPartsProfiles::
  423. #endif
  424. WebDataServiceFactory::GetInstance();
  425. webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
  426. + user_scripts::UserScriptsBrowserClient::GetInstance();
  427. }
  428. void ChromeBrowserMainExtraPartsProfiles::PreProfileInit() {
  429. diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
  430. --- a/chrome/browser/profiles/profile_manager.cc
  431. +++ b/chrome/browser/profiles/profile_manager.cc
  432. @@ -115,6 +115,8 @@
  433. #include "extensions/common/manifest.h"
  434. #endif
  435. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  436. +
  437. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  438. #include "chrome/browser/sessions/app_session_service_factory.h"
  439. #include "chrome/browser/sessions/session_service_factory.h"
  440. @@ -1706,6 +1708,13 @@ void ProfileManager::DoFinalInitForServices(Profile* profile,
  441. #endif
  442. #endif
  443. +
  444. + user_scripts::UserScriptsBrowserClient* userscript_client =
  445. + user_scripts::UserScriptsBrowserClient::GetInstance();
  446. + if (userscript_client) {
  447. + userscript_client->SetProfile(profile);
  448. + }
  449. +
  450. #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  451. // Initialization needs to happen after extension system initialization (for
  452. // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the
  453. diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
  454. --- a/chrome/browser/profiles/renderer_updater.cc
  455. +++ b/chrome/browser/profiles/renderer_updater.cc
  456. @@ -31,6 +31,8 @@
  457. #include "chrome/browser/ash/login/signin/oauth2_login_manager_factory.h"
  458. #endif
  459. +#include "components/user_scripts/browser/user_script_prefs.h"
  460. +
  461. RendererUpdater::RendererUpdater(Profile* profile)
  462. : profile_(profile),
  463. is_off_the_record_(profile_->IsOffTheRecord()),
  464. @@ -51,6 +53,7 @@ RendererUpdater::RendererUpdater(Profile* profile)
  465. force_google_safesearch_.Init(prefs::kForceGoogleSafeSearch, pref_service);
  466. force_youtube_restrict_.Init(prefs::kForceYouTubeRestrict, pref_service);
  467. allowed_domains_for_apps_.Init(prefs::kAllowedDomainsForApps, pref_service);
  468. + activate_userscripts_.Init(user_scripts::prefs::kUserScriptsEnabled, pref_service);
  469. pref_change_registrar_.Init(pref_service);
  470. pref_change_registrar_.Add(
  471. @@ -65,6 +68,10 @@ RendererUpdater::RendererUpdater(Profile* profile)
  472. prefs::kAllowedDomainsForApps,
  473. base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  474. base::Unretained(this)));
  475. + pref_change_registrar_.Add(
  476. + user_scripts::prefs::kUserScriptsEnabled,
  477. + base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  478. + base::Unretained(this)));
  479. }
  480. RendererUpdater::~RendererUpdater() {
  481. @@ -188,5 +195,6 @@ chrome::mojom::DynamicParamsPtr RendererUpdater::CreateRendererDynamicParams()
  482. const {
  483. return chrome::mojom::DynamicParams::New(
  484. force_google_safesearch_.GetValue(), force_youtube_restrict_.GetValue(),
  485. - allowed_domains_for_apps_.GetValue());
  486. + allowed_domains_for_apps_.GetValue(),
  487. + activate_userscripts_.GetValue());
  488. }
  489. diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
  490. --- a/chrome/browser/profiles/renderer_updater.h
  491. +++ b/chrome/browser/profiles/renderer_updater.h
  492. @@ -93,6 +93,7 @@ class RendererUpdater : public KeyedService,
  493. // Prefs that we sync to the renderers.
  494. BooleanPrefMember force_google_safesearch_;
  495. + BooleanPrefMember activate_userscripts_;
  496. IntegerPrefMember force_youtube_restrict_;
  497. StringPrefMember allowed_domains_for_apps_;
  498. };
  499. diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  500. --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  501. +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  502. @@ -91,6 +91,7 @@
  503. #include "components/security_interstitials/content/urls.h"
  504. #include "components/signin/public/base/signin_buildflags.h"
  505. #include "components/site_engagement/content/site_engagement_service.h"
  506. +#include "components/user_scripts/browser/ui/user_scripts_ui.h"
  507. #include "content/public/browser/web_contents.h"
  508. #include "content/public/browser/web_ui.h"
  509. #include "content/public/common/content_client.h"
  510. @@ -811,6 +812,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
  511. return &NewWebUI<UserActionsUI>;
  512. if (url.host_piece() == chrome::kChromeUIVersionHost)
  513. return &NewWebUI<VersionUI>;
  514. + if (url.host_piece() == user_scripts::kChromeUIUserScriptsHost)
  515. + return &NewWebUI<user_scripts::UserScriptsUI>;
  516. #if !BUILDFLAG(IS_ANDROID)
  517. #if !BUILDFLAG(IS_CHROMEOS)
  518. diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
  519. --- a/chrome/chrome_paks.gni
  520. +++ b/chrome/chrome_paks.gni
  521. @@ -108,6 +108,7 @@ template("chrome_extra_paks") {
  522. "$root_gen_dir/skia/skia_resources.pak",
  523. "$root_gen_dir/third_party/blink/public/resources/blink_resources.pak",
  524. "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak",
  525. + "$root_gen_dir/chrome/userscripts_browser_resources.pak",
  526. "$root_gen_dir/ui/resources/webui_generated_resources.pak",
  527. ]
  528. deps = [
  529. @@ -128,6 +129,7 @@ template("chrome_extra_paks") {
  530. "//third_party/blink/public:devtools_inspector_resources",
  531. "//third_party/blink/public:resources",
  532. "//ui/resources",
  533. + "//components/user_scripts/browser:userscripts_browser_resources_grit",
  534. ]
  535. if (defined(invoker.deps)) {
  536. deps += invoker.deps
  537. diff --git a/chrome/common/renderer_configuration.mojom b/chrome/common/renderer_configuration.mojom
  538. --- a/chrome/common/renderer_configuration.mojom
  539. +++ b/chrome/common/renderer_configuration.mojom
  540. @@ -12,6 +12,7 @@ struct DynamicParams {
  541. bool force_safe_search = true;
  542. int32 youtube_restrict = 0;
  543. string allowed_domains_for_apps;
  544. + bool allow_userscript = false;
  545. };
  546. interface ChromeOSListener {
  547. diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
  548. --- a/chrome/renderer/BUILD.gn
  549. +++ b/chrome/renderer/BUILD.gn
  550. @@ -141,6 +141,7 @@ static_library("renderer") {
  551. "//components/content_capture/common",
  552. "//components/content_capture/renderer",
  553. "//components/content_settings/common:mojom",
  554. + "//components/user_scripts/renderer",
  555. "//components/content_settings/renderer",
  556. "//components/continuous_search/renderer",
  557. "//components/dom_distiller/content/renderer",
  558. diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
  559. --- a/chrome/renderer/chrome_content_renderer_client.cc
  560. +++ b/chrome/renderer/chrome_content_renderer_client.cc
  561. @@ -247,6 +247,9 @@
  562. #include "chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h"
  563. #endif
  564. +#include "components/user_scripts/common/user_scripts_features.h"
  565. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  566. +
  567. using autofill::AutofillAgent;
  568. using autofill::PasswordAutofillAgent;
  569. using autofill::PasswordGenerationAgent;
  570. @@ -419,6 +422,12 @@ void ChromeContentRendererClient::RenderThreadStarted() {
  571. WebString::FromASCII(extensions::kExtensionScheme));
  572. #endif
  573. + user_scripts::UserScriptsRendererClient* userscript_client =
  574. + user_scripts::UserScriptsRendererClient::GetInstance();
  575. + if (userscript_client) {
  576. + userscript_client->RenderThreadStarted();
  577. + }
  578. +
  579. #if BUILDFLAG(ENABLE_SPELLCHECK)
  580. if (!spellcheck_)
  581. InitSpellCheck();
  582. @@ -557,6 +566,13 @@ void ChromeContentRendererClient::RenderFrameCreated(
  583. render_frame, registry);
  584. #endif
  585. + user_scripts::UserScriptsRendererClient* userscript_client =
  586. + user_scripts::UserScriptsRendererClient::GetInstance();
  587. + if (userscript_client) {
  588. + userscript_client->RenderFrameCreated(
  589. + render_frame, registry);
  590. + }
  591. +
  592. #if BUILDFLAG(ENABLE_PLUGINS)
  593. new PepperHelper(render_frame);
  594. #endif
  595. @@ -1544,7 +1560,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentStart(
  596. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentStart(
  597. render_frame);
  598. // |render_frame| might be dead by now.
  599. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  600. #endif
  601. + user_scripts::UserScriptsRendererClient* userscript_client =
  602. + user_scripts::UserScriptsRendererClient::GetInstance();
  603. + if (userscript_client) {
  604. + userscript_client->RunScriptsAtDocumentStart(
  605. + render_frame);
  606. + }
  607. }
  608. void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  609. @@ -1553,7 +1576,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  610. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentEnd(
  611. render_frame);
  612. // |render_frame| might be dead by now.
  613. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  614. #endif
  615. + user_scripts::UserScriptsRendererClient* userscript_client =
  616. + user_scripts::UserScriptsRendererClient::GetInstance();
  617. + if (userscript_client) {
  618. + userscript_client->RunScriptsAtDocumentEnd(
  619. + render_frame);
  620. + }
  621. }
  622. void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  623. @@ -1562,7 +1592,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  624. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentIdle(
  625. render_frame);
  626. // |render_frame| might be dead by now.
  627. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  628. #endif
  629. + user_scripts::UserScriptsRendererClient* userscript_client =
  630. + user_scripts::UserScriptsRendererClient::GetInstance();
  631. + if (userscript_client) {
  632. + userscript_client->RunScriptsAtDocumentIdle(
  633. + render_frame);
  634. + }
  635. }
  636. void ChromeContentRendererClient::
  637. diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc
  638. --- a/chrome/renderer/chrome_render_thread_observer.cc
  639. +++ b/chrome/renderer/chrome_render_thread_observer.cc
  640. @@ -57,6 +57,8 @@
  641. #include "third_party/blink/public/web/web_security_policy.h"
  642. #include "third_party/blink/public/web/web_view.h"
  643. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  644. +
  645. #if BUILDFLAG(ENABLE_EXTENSIONS)
  646. #include "extensions/renderer/localization_peer.h"
  647. #endif
  648. @@ -254,6 +256,7 @@ void ChromeRenderThreadObserver::SetInitialConfiguration(
  649. void ChromeRenderThreadObserver::SetConfiguration(
  650. chrome::mojom::DynamicParamsPtr params) {
  651. *GetDynamicConfigParams() = std::move(*params);
  652. + user_scripts::UserScriptsRendererClient::GetInstance()->ConfigurationUpdated();
  653. }
  654. void ChromeRenderThreadObserver::OnRendererConfigurationAssociatedRequest(
  655. diff --git a/components/components_strings.grd b/components/components_strings.grd
  656. --- a/components/components_strings.grd
  657. +++ b/components/components_strings.grd
  658. @@ -336,6 +336,7 @@
  659. <part file="user_education_strings.grdp" />
  660. <part file="version_ui_strings.grdp" />
  661. <part file="webapps_strings.grdp" />
  662. + <part file="user_scripts/strings/userscripts_strings.grdp" />
  663. <if expr="not is_ios">
  664. <part file="management_strings.grdp" />
  665. diff --git a/components/user_scripts/README.md b/components/user_scripts/README.md
  666. new file mode 100644
  667. --- /dev/null
  668. +++ b/components/user_scripts/README.md
  669. @@ -0,0 +1,150 @@
  670. +# Userscripts support for Bromite
  671. +
  672. +UserScript support is under user setting currently disabled by default: when disabled, no code that can impact navigation safety is active.
  673. +
  674. +Activation allows the use of userscripts in Bromite. It is possible to add them in two ways:
  675. +- by selecting files from the file picker in the settings
  676. +- downloading the scripts and opening it from downloads (only if ends with .user.js)
  677. +The new imported scripts are disabled by default: they can be activated via the menu visible on the ui.
  678. +
  679. +Userscript support is currently the one provided by the desktop version. The enabled headers are:
  680. +
  681. +- `@name`
  682. +- `@version`
  683. +- `@description`
  684. +- `@url` or `@homepage`
  685. +- `@include`, `@exclude`, `@match`, `@exclude_match` for the url pattern (only http e https)
  686. +- `@run-at`
  687. + - `document-start`
  688. + Start the script after the documentElement is created, but before anything else happens
  689. + - `document-end`
  690. + Start the script after the entire document is parsed. Same as DOMContentLoaded
  691. + - `document-idle`
  692. + Start the script sometime after DOMContentLoaded, as soon as the document is "idle". Currently this uses the simple heuristic of: min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no particular injection point is guaranteed
  693. +
  694. +The url-patterns are so defined:
  695. +```
  696. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  697. +// <scheme> := '*' | 'http' | 'https'
  698. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  699. +// '*.' <anychar except '/' and '*'>+
  700. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  701. +// <path> := '/' <any chars>
  702. +//
  703. +// * Host is not used when the scheme is 'file'.
  704. +// * The path can have embedded '*' characters which act as glob wildcards.
  705. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  706. +// a valid scheme (as specified by valid_schemes_).
  707. +// * The '*' scheme pattern excludes file URLs.
  708. +//
  709. +// Examples of valid patterns:
  710. +// - http://*/*
  711. +// - http://*/foo*
  712. +// - https://*.google.com/foo*bar
  713. +// - file://monkey*
  714. +// - http://127.0.0.1/*
  715. +// - http://[2607:f8b0:4005:805::200e]/*
  716. +//
  717. +// Examples of invalid patterns:
  718. +// - http://* -- path not specified
  719. +// - http://*foo/bar -- * not allowed as substring of host component
  720. +// - http://foo.*.bar/baz -- * must be first component
  721. +// - http:/bar -- scheme separator not found
  722. +// - foo://* -- invalid scheme
  723. +// - chrome:// -- we don't support chrome internal URLs
  724. +```
  725. +
  726. +---
  727. +## **Beware of the scripts you enter: they can be a source of security problems, you are injecting code into your navigation**.
  728. +---
  729. +## Technical aspects
  730. +
  731. +`user_scripts/common` and `user_scripts/renderer` is the closest to the current chromium code: few changes there, mostly eliminated the superfluous extension related code.
  732. +
  733. +In `user_scripts/browser` you find the actual management (in the browser process) and in `android` basically the settings ui.
  734. +
  735. +At startup it tries to read all files in the `userscripts folder` in `/data/user/0/org.bromite.bromite/app_chrome/userscripts`: this could be a critical process because a crash would prevent the browser from opening, and that's why there is a crash counter that automatically disables the feature after three attempts if it encounters a problem during startup.
  736. +
  737. +The java ui allows userscript management: addition, deletion and activation/deactivation. Any errors while reading the scripts are presented to the user: scripts with errors cannot be activated. There is also the visualization of the script source and the open of its homepage (if foreseen) in incognito browsing.
  738. +
  739. +There is also support for an on-line help at https://github.com/bromite/bromite/wiki/UserScripts.
  740. +
  741. +
  742. +Entry points are `components/user_scripts/browser/userscripts_browser_client.cc` and `components/user_scripts/renderer/user_scripts_renderer_client.cc`: the two attach to the browser and the renderer process.
  743. +
  744. +for userscripts_browser_client.cc
  745. +- `chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc`
  746. +builds the browser side. also gpu process passes here, but the call is avoided.
  747. +
  748. +- `chrome/browser/profiles/profile_manager.cc`
  749. +set the profile
  750. +
  751. +for renderer/user_scripts_renderer_client.cc
  752. +- `chrome/renderer/chrome_content_renderer_client.cc`
  753. +at the renderer side
  754. +
  755. +the two sides have a life of their own and can communicate only via ipc, the renderer does not have access to the disk while the browser does only via its own task runner file (`components/user_scripts/browser/file_task_runner.cc`).
  756. +
  757. +## BROWSER PROCESS
  758. +Once the profile is set, it istance the `components/user_scripts/browser/user_script_loader.cc` and starts it.
  759. +This loads all the files in the folder into the runner file and interprets them. Control then passes to
  760. +`components/user_scripts/browser/user_script_prefs.cc` which verifies through the default profile what the user wants active.
  761. +At that point it passes through IPC to the renderer only the list of active scripts.
  762. +
  763. +## RENDERER PROCESS
  764. +Each time a frame is created, the script pattern is checked and it is injected into the three stages (START, IDLE, END).
  765. +The logic is all in `components/user_scripts/renderer/user_script_set.cc`.
  766. +
  767. +## Simple example
  768. +Here you find a working example that eliminates the google popup, useful in always incognito:
  769. +```
  770. +// ==UserScript==
  771. +// @name Remove Google Consent
  772. +// @namespace google
  773. +// @version 0.0.1
  774. +// @description Autohide Accepts Cookies
  775. +// @author uazo
  776. +// @match https://*.google.com/search?*
  777. +// @grant none
  778. +// @run-at document-start
  779. +// ==/UserScript==
  780. +
  781. +(function() {
  782. + 'use strict';
  783. +
  784. + var prepareStyleSheet = function() {
  785. + var style = document.createElement('style');
  786. + //style.setAttribute('media', 'screen');
  787. + style.appendChild(document.createTextNode(''));
  788. + document.head.appendChild(style);
  789. + style.sheet.insertRule('body { overflow:scroll !important;position:unset !important }');
  790. + };
  791. +
  792. + var hideConsent = function() {
  793. + document.getElementById("lb").style.display = "none";
  794. + };
  795. +
  796. + var checkElementThenRun = function(selector, func) {
  797. + var el = document.querySelector(selector);
  798. + if ( el == null ) {
  799. + if (window.requestAnimationFrame != undefined) {
  800. + window.requestAnimationFrame(function(){ checkElementThenRun(selector, func)});
  801. + } else {
  802. + document.addEventListener('readystatechange', function(e) {
  803. + if (document.readyState == 'complete') {
  804. + func();
  805. + }
  806. + });
  807. + }
  808. + } else {
  809. + func();
  810. + }
  811. + }
  812. +
  813. + document.cookie = 'CONSENT=YES+IT.it+V13+BX;domain=.google.com';
  814. + checkElementThenRun('head', prepareStyleSheet);
  815. + checkElementThenRun('#lb', hideConsent);
  816. +})();
  817. +```
  818. +
  819. +See also: https://github.com/bromite/bromite/pull/857
  820. diff --git a/components/user_scripts/android/BUILD.gn b/components/user_scripts/android/BUILD.gn
  821. new file mode 100755
  822. --- /dev/null
  823. +++ b/components/user_scripts/android/BUILD.gn
  824. @@ -0,0 +1,83 @@
  825. +# This file is part of Bromite.
  826. +
  827. +# Bromite is free software: you can redistribute it and/or modify
  828. +# it under the terms of the GNU General Public License as published by
  829. +# the Free Software Foundation, either version 3 of the License, or
  830. +# (at your option) any later version.
  831. +
  832. +# Bromite is distributed in the hope that it will be useful,
  833. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  834. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  835. +# GNU General Public License for more details.
  836. +
  837. +# You should have received a copy of the GNU General Public License
  838. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  839. +
  840. +import("//build/config/android/rules.gni")
  841. +
  842. +generate_jni("user_scripts_jni_headers") {
  843. + sources = [ "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java" ]
  844. +}
  845. +
  846. +android_resources("java_resources") {
  847. + sources = [
  848. + "java/res/xml/userscripts_preferences.xml",
  849. + "java/res/layout/accept_script_item.xml",
  850. + "java/res/layout/accept_script_list.xml",
  851. + "java/res/layout/scripts_preference.xml",
  852. + "java/res/values/dimens.xml"
  853. + ]
  854. +
  855. + deps = [
  856. + "//components/browser_ui/strings/android:browser_ui_strings_grd",
  857. + "//components/browser_ui/styles/android:java_resources",
  858. + "//components/strings:components_strings_grd",
  859. + "//ui/android:ui_java_resources",
  860. + ]
  861. +}
  862. +
  863. +android_library("java") {
  864. + sources = [
  865. + "java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java",
  866. + "java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java",
  867. + "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java",
  868. + "java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java",
  869. + "java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java",
  870. + "java/src/org/chromium/components/user_scripts/ScriptListPreference.java",
  871. + "java/src/org/chromium/components/user_scripts/ScriptInfo.java",
  872. + ]
  873. + deps = [
  874. + ":java_resources",
  875. + "//base:base_java",
  876. + "//base:jni_java",
  877. + "//components/embedder_support/android:browser_context_java",
  878. + "//components/browser_ui/settings/android:java",
  879. + "//components/browser_ui/widget/android:java",
  880. + "//content/public/android:content_java",
  881. + "//components/prefs/android:java",
  882. + "//build/android:build_java",
  883. + "//third_party/androidx:androidx_fragment_fragment_java",
  884. + "//third_party/androidx:androidx_recyclerview_recyclerview_java",
  885. + "//third_party/androidx:androidx_annotation_annotation_java",
  886. + "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
  887. + "//third_party/androidx:androidx_preference_preference_java",
  888. + "//third_party/androidx:androidx_core_core_java",
  889. + "//ui/android:ui_java",
  890. + ]
  891. + resources_package = "org.chromium.components.user_scripts"
  892. + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
  893. +}
  894. +
  895. +source_set("android") {
  896. + sources = [
  897. + "user_scripts_bridge.cc",
  898. + "user_scripts_bridge.h",
  899. + ]
  900. + deps = [
  901. + ":user_scripts_jni_headers",
  902. + "//base",
  903. + "//components/user_scripts/browser",
  904. + "//components/permissions",
  905. + "//content/public/browser",
  906. + ]
  907. +}
  908. diff --git a/components/user_scripts/android/java/res/layout/accept_script_item.xml b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  909. new file mode 100644
  910. --- /dev/null
  911. +++ b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  912. @@ -0,0 +1,160 @@
  913. +<?xml version="1.0" encoding="utf-8"?>
  914. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  915. + Use of this source code is governed by a BSD-style license that can be
  916. + found in the LICENSE file. -->
  917. +
  918. +<LinearLayout
  919. + xmlns:android="http://schemas.android.com/apk/res/android"
  920. + xmlns:app="http://schemas.android.com/apk/res-auto"
  921. + xmlns:tools="http://schemas.android.com/tools"
  922. + android:layout_width="match_parent"
  923. + android:layout_height="wrap_content"
  924. + android:orientation="vertical"
  925. + android:layout_gravity="center_vertical" >
  926. +
  927. + <LinearLayout
  928. + android:layout_marginStart="0dp"
  929. + android:paddingStart="@dimen/draggable_list_item_padding"
  930. + android:paddingEnd="@dimen/draggable_list_item_padding"
  931. + style="@style/ListItemContainer">
  932. +
  933. + <Switch
  934. + android:id="@+id/switch_widget"
  935. + android:layout_width="wrap_content"
  936. + android:layout_height="wrap_content"
  937. + android:paddingEnd="15dp"
  938. + android:focusable="false"
  939. + android:background="@null" />
  940. +
  941. + <LinearLayout
  942. + android:layout_width="0dp"
  943. + android:layout_height="wrap_content"
  944. + android:layout_weight="1"
  945. + android:orientation="vertical"
  946. + android:layout_gravity="center_vertical" >
  947. +
  948. + <TextView
  949. + android:id="@+id/title"
  950. + android:layout_width="match_parent"
  951. + android:layout_height="wrap_content"
  952. + style="@style/PreferenceTitle" />
  953. +
  954. + <TextView
  955. + android:id="@+id/description"
  956. + android:layout_width="match_parent"
  957. + android:layout_height="wrap_content"
  958. + style="@style/PreferenceSummary" />
  959. +
  960. + <LinearLayout
  961. + android:layout_width="match_parent"
  962. + android:layout_height="wrap_content"
  963. + android:layout_weight="1"
  964. + android:paddingTop="5dp"
  965. + android:layout_gravity="center_vertical" >
  966. +
  967. + <TextView
  968. + android:layout_width="wrap_content"
  969. + android:layout_height="wrap_content"
  970. + android:paddingEnd="5dp"
  971. + style="@style/PreferenceSummary"
  972. + android:text="@string/scripts_item_version"
  973. + android:textStyle="bold" />
  974. +
  975. + <TextView
  976. + android:id="@+id/version"
  977. + android:layout_width="match_parent"
  978. + android:layout_height="wrap_content"
  979. + style="@style/PreferenceSummary" />
  980. +
  981. + </LinearLayout>
  982. +
  983. + <LinearLayout
  984. + android:layout_width="match_parent"
  985. + android:layout_height="wrap_content"
  986. + android:layout_weight="1"
  987. + android:layout_gravity="center_vertical" >
  988. +
  989. + <TextView
  990. + android:layout_width="wrap_content"
  991. + android:layout_height="wrap_content"
  992. + android:paddingEnd="5dp"
  993. + style="@style/PreferenceSummary"
  994. + android:text="@string/scripts_item_filename"
  995. + android:textStyle="bold" />
  996. +
  997. + <TextView
  998. + android:id="@+id/file"
  999. + android:layout_width="match_parent"
  1000. + android:layout_height="wrap_content"
  1001. + style="@style/PreferenceSummary" />
  1002. +
  1003. + </LinearLayout>
  1004. +
  1005. + <LinearLayout
  1006. + android:id="@+id/url_container"
  1007. + android:layout_width="match_parent"
  1008. + android:layout_height="wrap_content"
  1009. + android:layout_weight="1"
  1010. + android:layout_gravity="center_vertical" >
  1011. +
  1012. + <TextView
  1013. + android:layout_width="wrap_content"
  1014. + android:layout_height="wrap_content"
  1015. + android:paddingEnd="5dp"
  1016. + style="@style/PreferenceSummary"
  1017. + android:text="@string/scripts_item_url"
  1018. + android:textStyle="bold" />
  1019. +
  1020. + <TextView
  1021. + android:id="@+id/url"
  1022. + android:layout_width="match_parent"
  1023. + android:layout_height="wrap_content"
  1024. + android:autoLink="web"
  1025. + android:focusable="true"
  1026. + android:linksClickable="true" />
  1027. +
  1028. + </LinearLayout>
  1029. +
  1030. + </LinearLayout>
  1031. +
  1032. + <org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
  1033. + android:id="@+id/more"
  1034. + android:layout_width="wrap_content"
  1035. + android:layout_height="match_parent"
  1036. + android:paddingStart="@dimen/default_list_row_padding"
  1037. + android:paddingEnd="@dimen/default_list_row_padding"
  1038. + android:background="@null"
  1039. + android:src="@drawable/ic_more_vert_24dp"
  1040. + app:menuMaxWidth="@dimen/pref_scripts_item_popup_width"
  1041. + app:tint="@color/default_icon_color_tint_list"
  1042. + tools:ignore="ContentDescription" />
  1043. +
  1044. + </LinearLayout>
  1045. +
  1046. + <LinearLayout
  1047. + android:id="@+id/error_layout"
  1048. + android:layout_marginStart="0dp"
  1049. + android:paddingStart="@dimen/draggable_list_item_padding"
  1050. + android:paddingEnd="2dp"
  1051. + android:layout_width="match_parent"
  1052. + android:layout_height="wrap_content"
  1053. + style="@style/ListItemContainer">
  1054. +
  1055. + <org.chromium.ui.widget.ChromeImageView
  1056. + android:id="@+id/icon"
  1057. + android:layout_width="40dp"
  1058. + android:layout_height="wrap_content"
  1059. + android:paddingEnd="15dp"
  1060. + android:adjustViewBounds="true"
  1061. + android:importantForAccessibility="no"
  1062. + app:srcCompat="@drawable/ic_error_outline_red_24dp"/>
  1063. +
  1064. + <TextView
  1065. + android:id="@+id/error"
  1066. + android:layout_width="match_parent"
  1067. + android:layout_height="wrap_content"
  1068. + android:textColor="#F00"
  1069. + style="@style/PreferenceSummary" />
  1070. +
  1071. + </LinearLayout>
  1072. +</LinearLayout>
  1073. \ No newline at end of file
  1074. diff --git a/components/user_scripts/android/java/res/layout/accept_script_list.xml b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  1075. new file mode 100644
  1076. --- /dev/null
  1077. +++ b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  1078. @@ -0,0 +1,10 @@
  1079. +<?xml version="1.0" encoding="utf-8"?>
  1080. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  1081. + Use of this source code is governed by a BSD-style license that can be
  1082. + found in the LICENSE file. -->
  1083. +
  1084. +<androidx.recyclerview.widget.RecyclerView
  1085. + xmlns:android="http://schemas.android.com/apk/res/android"
  1086. + android:id="@+id/script_list"
  1087. + android:layout_width="match_parent"
  1088. + android:layout_height="wrap_content" />
  1089. \ No newline at end of file
  1090. diff --git a/components/user_scripts/android/java/res/layout/scripts_preference.xml b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  1091. new file mode 100644
  1092. --- /dev/null
  1093. +++ b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  1094. @@ -0,0 +1,40 @@
  1095. +<?xml version="1.0" encoding="utf-8"?>
  1096. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  1097. + Use of this source code is governed by a BSD-style license that can be
  1098. + found in the LICENSE file. -->
  1099. +
  1100. +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  1101. + android:id="@+id/accept_scripts_list_container"
  1102. + style="@style/PreferenceLayout"
  1103. + android:layout_width="match_parent"
  1104. + android:layout_height="wrap_content"
  1105. + android:paddingStart="0dp"
  1106. + android:paddingEnd="0dp"
  1107. + android:padding="0dp"
  1108. + android:orientation="vertical" >
  1109. +
  1110. + <TextView
  1111. + android:layout_width="match_parent"
  1112. + android:layout_height="wrap_content"
  1113. + android:padding="@dimen/draggable_list_item_padding"
  1114. + android:text="@string/scripts_list_description" />
  1115. +
  1116. + <FrameLayout
  1117. + android:id="@android:id/widget_frame"
  1118. + android:layout_width="match_parent"
  1119. + android:layout_height="wrap_content" />
  1120. +
  1121. + <TextView
  1122. + android:id="@+id/add_script"
  1123. + android:layout_width="match_parent"
  1124. + android:layout_height="wrap_content"
  1125. + android:background="?attr/selectableItemBackground"
  1126. + android:clickable="true"
  1127. + android:gravity="center_vertical"
  1128. + android:padding="@dimen/draggable_list_item_padding"
  1129. + android:paddingStart="@dimen/pref_scripts_add_button_padding"
  1130. + android:drawablePadding="@dimen/pref_scripts_add_button_padding"
  1131. + android:text="@string/add_script"
  1132. + style="@style/PreferenceTitle" />
  1133. +
  1134. +</LinearLayout>
  1135. \ No newline at end of file
  1136. diff --git a/components/user_scripts/android/java/res/values/dimens.xml b/components/user_scripts/android/java/res/values/dimens.xml
  1137. new file mode 100755
  1138. --- /dev/null
  1139. +++ b/components/user_scripts/android/java/res/values/dimens.xml
  1140. @@ -0,0 +1,11 @@
  1141. +<?xml version="1.0" encoding="utf-8"?>
  1142. +<!-- Copyright 2014 The Chromium Authors. All rights reserved.
  1143. + Use of this source code is governed by a BSD-style license that can be
  1144. + found in the LICENSE file. -->
  1145. +
  1146. +<resources xmlns:tools="http://schemas.android.com/tools">
  1147. +
  1148. + <dimen name="pref_scripts_add_button_padding">24dp</dimen>
  1149. + <dimen name="pref_scripts_item_popup_width">260dp</dimen>
  1150. +
  1151. +</resources>
  1152. diff --git a/components/user_scripts/android/java/res/xml/userscripts_preferences.xml b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1153. new file mode 100644
  1154. --- /dev/null
  1155. +++ b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1156. @@ -0,0 +1,34 @@
  1157. +<?xml version="1.0" encoding="utf-8"?>
  1158. +<!--
  1159. + This file is part of Bromite.
  1160. +
  1161. + Bromite is free software: you can redistribute it and/or modify
  1162. + it under the terms of the GNU General Public License as published by
  1163. + the Free Software Foundation, either version 3 of the License, or
  1164. + (at your option) any later version.
  1165. +
  1166. + Bromite is distributed in the hope that it will be useful,
  1167. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1168. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1169. + GNU General Public License for more details.
  1170. +
  1171. + You should have received a copy of the GNU General Public License
  1172. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1173. +-->
  1174. +
  1175. +<PreferenceScreen
  1176. + xmlns:android="http://schemas.android.com/apk/res/android"
  1177. + xmlns:app="http://schemas.android.com/apk/res-auto">
  1178. +
  1179. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  1180. + android:key="enabled_switch"
  1181. + android:title="@string/option_userscript_flag"
  1182. + android:summaryOn="@string/option_userscript_flag_on"
  1183. + android:summaryOff="@string/option_userscript_flag_off" />
  1184. +
  1185. + <org.chromium.components.user_scripts.ScriptListPreference
  1186. + android:key="script_list"
  1187. + android:layout="@layout/scripts_preference"
  1188. + android:widgetLayout="@layout/accept_script_list" />
  1189. +
  1190. +</PreferenceScreen>
  1191. diff --git a/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  1192. new file mode 100755
  1193. --- /dev/null
  1194. +++ b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  1195. @@ -0,0 +1,87 @@
  1196. +/*
  1197. + This file is part of Bromite.
  1198. +
  1199. + Bromite is free software: you can redistribute it and/or modify
  1200. + it under the terms of the GNU General Public License as published by
  1201. + the Free Software Foundation, either version 3 of the License, or
  1202. + (at your option) any later version.
  1203. +
  1204. + Bromite is distributed in the hope that it will be useful,
  1205. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1206. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1207. + GNU General Public License for more details.
  1208. +
  1209. + You should have received a copy of the GNU General Public License
  1210. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1211. +*/
  1212. +
  1213. +package org.chromium.chrome.browser.user_scripts;
  1214. +
  1215. +import android.content.Context;
  1216. +import android.content.Intent;
  1217. +import android.provider.Browser;
  1218. +import android.provider.MediaStore;
  1219. +import android.net.Uri;
  1220. +
  1221. +import org.chromium.base.ContextUtils;
  1222. +import org.chromium.base.ContentUriUtils;
  1223. +import org.chromium.base.IntentUtils;
  1224. +
  1225. +import org.chromium.chrome.browser.IntentHandler;
  1226. +import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  1227. +import org.chromium.components.browser_ui.settings.SettingsLauncher;
  1228. +
  1229. +import org.chromium.components.user_scripts.UserScriptsPreferences;
  1230. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1231. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1232. +
  1233. +public class UserScriptsUtils implements IUserScriptsUtils
  1234. +{
  1235. + private static UserScriptsUtils instance;
  1236. +
  1237. + private UserScriptsUtils() {}
  1238. +
  1239. + public static void Initialize() {
  1240. + instance = new UserScriptsUtils();
  1241. + UserScriptsBridge.registerUtils(instance);
  1242. + }
  1243. +
  1244. + public static UserScriptsUtils getInstance() {
  1245. + if (instance == null) Initialize();
  1246. + return instance;
  1247. + }
  1248. +
  1249. + public boolean openFile(String filePath, String mimeType, String downloadGuid,
  1250. + String originalUrl, String referrer, Uri contentUri) {
  1251. + if (UserScriptsBridge.isEnabled() == false) return false;
  1252. +
  1253. + Context context = ContextUtils.getApplicationContext();
  1254. +
  1255. + String visibleName = filePath;
  1256. + if (ContentUriUtils.isContentUri(visibleName)) {
  1257. + visibleName = ContentUriUtils.getDisplayName(contentUri, context,
  1258. + MediaStore.MediaColumns.DISPLAY_NAME);
  1259. + }
  1260. +
  1261. + if (visibleName.toUpperCase().endsWith(".USER.JS") == false) return false;
  1262. +
  1263. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  1264. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  1265. + context, UserScriptsPreferences.class.getName(),
  1266. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  1267. + IntentUtils.safeStartActivity(context, intent);
  1268. +
  1269. + return true;
  1270. + }
  1271. +
  1272. + public void openSourceFile(String scriptKey) {
  1273. + Context context = ContextUtils.getApplicationContext();
  1274. +
  1275. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("chrome://user-scripts/?key=" + scriptKey));
  1276. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1277. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1278. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1279. + intent.setPackage(context.getPackageName());
  1280. + IntentHandler.startChromeLauncherActivityForTrustedIntent(intent);
  1281. + }
  1282. +}
  1283. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1284. new file mode 100644
  1285. --- /dev/null
  1286. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1287. @@ -0,0 +1,90 @@
  1288. +// Copyright 2019 The Chromium Authors. All rights reserved.
  1289. +// Use of this source code is governed by a BSD-style license that can be
  1290. +// found in the LICENSE file.
  1291. +
  1292. +package org.chromium.components.user_scripts;
  1293. +
  1294. +import android.annotation.TargetApi;
  1295. +import android.app.Activity;
  1296. +import android.content.Context;
  1297. +import android.content.Intent;
  1298. +import android.content.IntentSender;
  1299. +import android.os.Build;
  1300. +import android.view.View;
  1301. +
  1302. +import androidx.fragment.app.Fragment;
  1303. +
  1304. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  1305. +import org.chromium.ui.base.ImmutableWeakReference;
  1306. +import org.chromium.ui.base.IntentRequestTracker;
  1307. +import org.chromium.ui.base.IntentRequestTracker.Delegate;
  1308. +import org.chromium.ui.base.WindowAndroid;
  1309. +
  1310. +import java.lang.ref.WeakReference;
  1311. +
  1312. +import org.chromium.ui.permissions.ActivityAndroidPermissionDelegate;
  1313. +
  1314. +/**
  1315. + * Implements intent sending for a fragment based window. This should be created when
  1316. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  1317. + */
  1318. +public class FragmentWindowAndroid extends WindowAndroid {
  1319. + private Fragment mFragment;
  1320. +
  1321. + private static class TrackerDelegateImpl implements Delegate {
  1322. + private final Fragment mFragment;
  1323. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  1324. + // every getActivity call. It is not needed for correctness.
  1325. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  1326. +
  1327. + /**
  1328. + * Create an instance of delegate for the given fragment that will own the
  1329. + * IntentRequestTracker.
  1330. + * @param fragment The fragment that owns the IntentRequestTracker.
  1331. + */
  1332. + private TrackerDelegateImpl(Fragment fragment) {
  1333. + mFragment = fragment;
  1334. + }
  1335. +
  1336. + @Override
  1337. + public boolean startActivityForResult(Intent intent, int requestCode) {
  1338. + mFragment.startActivityForResult(intent, requestCode, null);
  1339. + return true;
  1340. + }
  1341. +
  1342. + @Override
  1343. + public boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  1344. + try {
  1345. + mFragment.startIntentSenderForResult(
  1346. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  1347. + } catch (IntentSender.SendIntentException e) {
  1348. + return false;
  1349. + }
  1350. + return true;
  1351. + }
  1352. +
  1353. + @Override
  1354. + public void finishActivity(int requestCode) {
  1355. + Activity activity = getActivity().get();
  1356. + if (activity == null) return;
  1357. + activity.finishActivity(requestCode);
  1358. + }
  1359. +
  1360. + @Override
  1361. + public final WeakReference<Activity> getActivity() {
  1362. + if (mActivityWeakRefHolder == null
  1363. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1364. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1365. + }
  1366. + return mActivityWeakRefHolder;
  1367. + }
  1368. + }
  1369. +
  1370. + FragmentWindowAndroid(Context context, Fragment fragment) {
  1371. + super(context, IntentRequestTracker.createFromDelegate(new TrackerDelegateImpl(fragment)));
  1372. + mFragment = fragment;
  1373. +
  1374. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  1375. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  1376. + }
  1377. +}
  1378. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1379. new file mode 100644
  1380. --- /dev/null
  1381. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1382. @@ -0,0 +1,22 @@
  1383. +/*
  1384. + This file is part of Bromite.
  1385. +
  1386. + Bromite is free software: you can redistribute it and/or modify
  1387. + it under the terms of the GNU General Public License as published by
  1388. + the Free Software Foundation, either version 3 of the License, or
  1389. + (at your option) any later version.
  1390. +
  1391. + Bromite is distributed in the hope that it will be useful,
  1392. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1393. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1394. + GNU General Public License for more details.
  1395. +
  1396. + You should have received a copy of the GNU General Public License
  1397. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1398. +*/
  1399. +
  1400. +package org.chromium.components.user_scripts;
  1401. +
  1402. +public interface IUserScriptsUtils {
  1403. + public void openSourceFile(String scriptKey);
  1404. +}
  1405. \ No newline at end of file
  1406. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1407. new file mode 100644
  1408. --- /dev/null
  1409. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1410. @@ -0,0 +1,37 @@
  1411. +/*
  1412. + This file is part of Bromite.
  1413. +
  1414. + Bromite is free software: you can redistribute it and/or modify
  1415. + it under the terms of the GNU General Public License as published by
  1416. + the Free Software Foundation, either version 3 of the License, or
  1417. + (at your option) any later version.
  1418. +
  1419. + Bromite is distributed in the hope that it will be useful,
  1420. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1421. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1422. + GNU General Public License for more details.
  1423. +
  1424. + You should have received a copy of the GNU General Public License
  1425. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1426. +*/
  1427. +
  1428. +package org.chromium.components.user_scripts;
  1429. +
  1430. +import java.time.LocalDateTime;
  1431. +
  1432. +public class ScriptInfo {
  1433. + public String Key;
  1434. + public String Name;
  1435. + public String Description;
  1436. + public String Version;
  1437. + public String FilePath;
  1438. + public String UrlSource;
  1439. +
  1440. + public boolean Enabled;
  1441. + public LocalDateTime InstallTime;
  1442. +
  1443. + public String ParserError;
  1444. + public boolean ForceDisabled;
  1445. +
  1446. + public ScriptInfo() {}
  1447. +}
  1448. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1449. new file mode 100644
  1450. --- /dev/null
  1451. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1452. @@ -0,0 +1,163 @@
  1453. +/*
  1454. + This file is part of Bromite.
  1455. +
  1456. + Bromite is free software: you can redistribute it and/or modify
  1457. + it under the terms of the GNU General Public License as published by
  1458. + the Free Software Foundation, either version 3 of the License, or
  1459. + (at your option) any later version.
  1460. +
  1461. + Bromite is distributed in the hope that it will be useful,
  1462. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1463. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1464. + GNU General Public License for more details.
  1465. +
  1466. + You should have received a copy of the GNU General Public License
  1467. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1468. +*/
  1469. +
  1470. +package org.chromium.components.user_scripts;
  1471. +
  1472. +import android.content.Context;
  1473. +import android.view.LayoutInflater;
  1474. +import android.view.MotionEvent;
  1475. +import android.view.View;
  1476. +import android.view.ViewGroup;
  1477. +import android.view.accessibility.AccessibilityManager;
  1478. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1479. +import android.widget.ImageView;
  1480. +import android.widget.TextView;
  1481. +import android.widget.Switch;
  1482. +import android.widget.CompoundButton;
  1483. +import android.widget.LinearLayout;
  1484. +
  1485. +import androidx.annotation.DrawableRes;
  1486. +import androidx.annotation.NonNull;
  1487. +import androidx.core.view.ViewCompat;
  1488. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1489. +
  1490. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1491. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1492. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1493. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1494. +import org.chromium.ui.widget.ChromeImageView;
  1495. +
  1496. +import java.util.ArrayList;
  1497. +import java.util.List;
  1498. +
  1499. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1500. +
  1501. + class ItemClickListener {
  1502. + void onScriptOnOff(boolean Enabled) {}
  1503. + void onScriptClicked() {}
  1504. + }
  1505. +
  1506. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1507. + private TextView mTitle;
  1508. + private TextView mDescription;
  1509. + private TextView mVersion;
  1510. + private TextView mFile;
  1511. + private TextView mUrl;
  1512. + private TextView mError;
  1513. + private Switch mSwitch;
  1514. + private ChromeImageView mIcon;
  1515. + private LinearLayout mErrorLayout;
  1516. + private LinearLayout mUrlContainer;
  1517. +
  1518. + private ListMenuButton mMoreButton;
  1519. +
  1520. + private CompoundButton.OnCheckedChangeListener mOnOffListener;
  1521. +
  1522. + ScriptInfoRowViewHolder(View view) {
  1523. + super(view);
  1524. +
  1525. + mSwitch = view.findViewById(R.id.switch_widget);
  1526. + mTitle = view.findViewById(R.id.title);
  1527. + mDescription = view.findViewById(R.id.description);
  1528. + mVersion = view.findViewById(R.id.version);
  1529. + mFile = view.findViewById(R.id.file);
  1530. + mUrl = view.findViewById(R.id.url);
  1531. + mUrlContainer = view.findViewById(R.id.url_container);
  1532. + mError = view.findViewById(R.id.error);
  1533. + mIcon = view.findViewById(R.id.icon);
  1534. + mErrorLayout = view.findViewById(R.id.error_layout);
  1535. +
  1536. + mMoreButton = view.findViewById(R.id.more);
  1537. + }
  1538. +
  1539. + protected void updateScriptInfo(ScriptInfo item) {
  1540. + mSwitch.setOnCheckedChangeListener(null);
  1541. + mSwitch.setChecked(item.Enabled);
  1542. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1543. +
  1544. + mSwitch.setEnabled(true);
  1545. + if (item.ForceDisabled) {
  1546. + mSwitch.setEnabled(false);
  1547. + }
  1548. +
  1549. + mTitle.setText(item.Name);
  1550. + mDescription.setText(item.Description);
  1551. + mVersion.setText(item.Version);
  1552. + mFile.setText(item.Key);
  1553. + mUrl.setText(item.UrlSource);
  1554. + mError.setText(item.ParserError);
  1555. +
  1556. + mUrl.setVisibility(View.VISIBLE);
  1557. + if (item.UrlSource == null || item.UrlSource.isEmpty()) {
  1558. + mUrlContainer.setVisibility(View.GONE);
  1559. + }
  1560. + mErrorLayout.setVisibility(View.VISIBLE);
  1561. + if (item.ParserError == null || item.ParserError.isEmpty()) {
  1562. + mErrorLayout.setVisibility(View.GONE);
  1563. + }
  1564. + }
  1565. +
  1566. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1567. + mMoreButton.setVisibility(View.VISIBLE);
  1568. + mMoreButton.setDelegate(delegate);
  1569. + // Set item row end padding 0 when MenuButton is visible.
  1570. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1571. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1572. + }
  1573. +
  1574. + void setItemListener(@NonNull ItemClickListener listener) {
  1575. + mOnOffListener = (buttonView, isChecked) -> listener.onScriptOnOff(isChecked);
  1576. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1577. + itemView.setOnClickListener(view -> listener.onScriptClicked());
  1578. + }
  1579. + }
  1580. +
  1581. + ScriptListBaseAdapter(Context context) {
  1582. + super(context);
  1583. + }
  1584. +
  1585. + @Override
  1586. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1587. + View row = LayoutInflater.from(viewGroup.getContext())
  1588. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1589. + return new ScriptInfoRowViewHolder(row);
  1590. + }
  1591. +
  1592. + @Override
  1593. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1594. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1595. + }
  1596. +
  1597. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1598. + mElements = new ArrayList<>(values);
  1599. + notifyDataSetChanged();
  1600. + }
  1601. +
  1602. + @Override
  1603. + protected void setOrder(List<ScriptInfo> order) {
  1604. + }
  1605. +
  1606. + @Override
  1607. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1608. + return isPassivelyDraggable(viewHolder);
  1609. + }
  1610. +
  1611. + @Override
  1612. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1613. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1614. + }
  1615. +}
  1616. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1617. new file mode 100644
  1618. --- /dev/null
  1619. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1620. @@ -0,0 +1,171 @@
  1621. +/*
  1622. + This file is part of Bromite.
  1623. +
  1624. + Bromite is free software: you can redistribute it and/or modify
  1625. + it under the terms of the GNU General Public License as published by
  1626. + the Free Software Foundation, either version 3 of the License, or
  1627. + (at your option) any later version.
  1628. +
  1629. + Bromite is distributed in the hope that it will be useful,
  1630. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1631. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1632. + GNU General Public License for more details.
  1633. +
  1634. + You should have received a copy of the GNU General Public License
  1635. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1636. +*/
  1637. +
  1638. +package org.chromium.components.user_scripts;
  1639. +
  1640. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1641. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1642. +
  1643. +import android.content.Context;
  1644. +import android.content.Intent;
  1645. +import android.provider.Browser;
  1646. +import android.net.Uri;
  1647. +import android.util.AttributeSet;
  1648. +import android.widget.TextView;
  1649. +import android.widget.Toast;
  1650. +
  1651. +import androidx.preference.Preference;
  1652. +import androidx.preference.PreferenceViewHolder;
  1653. +import androidx.recyclerview.widget.DividerItemDecoration;
  1654. +import androidx.recyclerview.widget.LinearLayoutManager;
  1655. +import androidx.recyclerview.widget.RecyclerView;
  1656. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1657. +
  1658. +import org.chromium.ui.base.WindowAndroid;
  1659. +import org.chromium.ui.base.ActivityWindowAndroid;
  1660. +
  1661. +import org.chromium.base.ApplicationStatus;
  1662. +import org.chromium.base.ContextUtils;
  1663. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1664. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1665. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1666. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1667. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1668. +
  1669. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1670. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1671. +
  1672. +import java.util.List;
  1673. +
  1674. +public class ScriptListPreference extends Preference {
  1675. + private static class ScriptListAdapter
  1676. + extends ScriptListBaseAdapter {
  1677. + private final Context mContext;
  1678. +
  1679. + ScriptListAdapter(Context context) {
  1680. + super(context);
  1681. + mContext = context;
  1682. + }
  1683. +
  1684. + @Override
  1685. + public void onBindViewHolder(ViewHolder holder, int position) {
  1686. + super.onBindViewHolder(holder, position);
  1687. +
  1688. + final ScriptInfo info = getItemByPosition(position);
  1689. +
  1690. + ModelList menuItems = new ModelList();
  1691. +
  1692. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1693. + menuItems.add(buildMenuListItem(R.string.scripts_view_source, 0, 0,
  1694. + info.ParserError == null || info.ParserError.isEmpty()));
  1695. +
  1696. + ListMenu.Delegate delegate = (model) -> {
  1697. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1698. + if (textId == R.string.remove) {
  1699. + UserScriptsBridge.RemoveScript(info.Key);
  1700. + } else if (textId == R.string.scripts_view_source) {
  1701. + UserScriptsBridge.getUtils().openSourceFile(info.Key);
  1702. + }
  1703. + };
  1704. + ((ScriptInfoRowViewHolder) holder)
  1705. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1706. + ((ScriptInfoRowViewHolder) holder)
  1707. + .setItemListener(new ScriptListBaseAdapter.ItemClickListener() {
  1708. + @Override
  1709. + public void onScriptOnOff(boolean Enabled) {
  1710. + UserScriptsBridge.SetScriptEnabled(info.Key, Enabled);
  1711. + }
  1712. +
  1713. + @Override
  1714. + public void onScriptClicked() {}
  1715. + });
  1716. + }
  1717. +
  1718. + // @Override
  1719. + public void onDataUpdated(boolean enabled) {
  1720. + List<ScriptInfo> list = UserScriptsBridge.getUserScriptItems();
  1721. + if (enabled == false) {
  1722. + for (ScriptInfo script : list) {
  1723. + script.ForceDisabled = true;
  1724. + }
  1725. + }
  1726. + setDisplayedScriptInfo(list);
  1727. + }
  1728. + }
  1729. +
  1730. + private TextView mAddButton;
  1731. + private RecyclerView mRecyclerView;
  1732. + private ScriptListAdapter mAdapter;
  1733. + private FragmentWindowAndroid mWindowAndroid;
  1734. +
  1735. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1736. + super(context, attrs);
  1737. + mAdapter = new ScriptListAdapter(context);
  1738. + }
  1739. +
  1740. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1741. + mWindowAndroid = windowAndroid;
  1742. + }
  1743. +
  1744. + @Override
  1745. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1746. + super.onBindViewHolder(holder);
  1747. +
  1748. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1749. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1750. + TintedDrawable.constructTintedDrawable(
  1751. + getContext(), R.drawable.plus, R.color.default_control_color_active_baseline),
  1752. + null, null, null);
  1753. + mAddButton.setOnClickListener(view -> {
  1754. + UserScriptsBridge.SelectAndAddScriptFromFile(mWindowAndroid);
  1755. + });
  1756. +
  1757. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1758. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1759. + mRecyclerView.setLayoutManager(layoutManager);
  1760. + mRecyclerView.addItemDecoration(
  1761. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1762. + mRecyclerView.setEnabled(this.isEnabled());
  1763. + UserScriptsBridge.RegisterLoadCallback(this);
  1764. +
  1765. + // We do not want the RecyclerView to be announced by screen readers every time
  1766. + // the view is bound.
  1767. + if (mRecyclerView.getAdapter() != mAdapter) {
  1768. + mRecyclerView.setAdapter(mAdapter);
  1769. + // Initialize script list.
  1770. + mAdapter.onDataUpdated(this.isEnabled());
  1771. + }
  1772. + }
  1773. +
  1774. + @Override
  1775. + public void setEnabled (boolean enabled) {
  1776. + super.setEnabled(enabled);
  1777. + if (mRecyclerView != null) mRecyclerView.setEnabled(enabled);
  1778. + NotifyScriptsChanged();
  1779. + }
  1780. +
  1781. + public void NotifyScriptsChanged() {
  1782. + mAdapter.onDataUpdated(this.isEnabled());
  1783. + }
  1784. +
  1785. + public void OnUserScriptLoaded(boolean result, String error) {
  1786. + if (result == false) {
  1787. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1788. + toast.show();
  1789. + }
  1790. + }
  1791. +}
  1792. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1793. new file mode 100644
  1794. --- /dev/null
  1795. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1796. @@ -0,0 +1,212 @@
  1797. +/*
  1798. + This file is part of Bromite.
  1799. +
  1800. + Bromite is free software: you can redistribute it and/or modify
  1801. + it under the terms of the GNU General Public License as published by
  1802. + the Free Software Foundation, either version 3 of the License, or
  1803. + (at your option) any later version.
  1804. +
  1805. + Bromite is distributed in the hope that it will be useful,
  1806. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1807. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1808. + GNU General Public License for more details.
  1809. +
  1810. + You should have received a copy of the GNU General Public License
  1811. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1812. +*/
  1813. +
  1814. +package org.chromium.components.user_scripts;
  1815. +
  1816. +import java.util.ArrayList;
  1817. +import java.util.List;
  1818. +import java.lang.ref.WeakReference;
  1819. +
  1820. +import org.json.JSONArray;
  1821. +import org.json.JSONException;
  1822. +import org.json.JSONObject;
  1823. +
  1824. +import android.content.Context;
  1825. +import android.content.Intent;
  1826. +import android.net.Uri;
  1827. +import android.provider.MediaStore;
  1828. +import androidx.annotation.Nullable;
  1829. +import android.app.AlertDialog;
  1830. +import android.content.DialogInterface;
  1831. +
  1832. +import org.chromium.base.annotations.CalledByNative;
  1833. +import org.chromium.base.annotations.JNINamespace;
  1834. +import org.chromium.base.annotations.NativeMethods;
  1835. +import org.chromium.base.ContentUriUtils;
  1836. +import org.chromium.base.Log;
  1837. +import org.chromium.ui.base.WindowAndroid;
  1838. +
  1839. +import org.chromium.components.user_scripts.ScriptListPreference;
  1840. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1841. +
  1842. +@JNINamespace("user_scripts")
  1843. +public class UserScriptsBridge {
  1844. + private static final String TAG = "UserScript";
  1845. +
  1846. + static WeakReference<ScriptListPreference> observer;
  1847. +
  1848. + private static IUserScriptsUtils utilInstance;
  1849. +
  1850. + public static void registerUtils(IUserScriptsUtils instance) {
  1851. + utilInstance = instance;
  1852. + }
  1853. +
  1854. + public static IUserScriptsUtils getUtils() {
  1855. + return utilInstance;
  1856. + }
  1857. +
  1858. + public static boolean isEnabled() {
  1859. + return UserScriptsBridgeJni.get().isEnabled();
  1860. + }
  1861. +
  1862. + public static void setEnabled(boolean enabled) {
  1863. + UserScriptsBridgeJni.get().setEnabled(enabled);
  1864. + }
  1865. +
  1866. + public static void RemoveScript(String key) {
  1867. + UserScriptsBridgeJni.get().removeScript(key);
  1868. + }
  1869. +
  1870. + public static void SetScriptEnabled(String key,
  1871. + boolean enabled) {
  1872. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1873. + }
  1874. +
  1875. + public static void Reload() {
  1876. + UserScriptsBridgeJni.get().reload();
  1877. + }
  1878. +
  1879. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1880. + Context context = window.getContext().get();
  1881. +
  1882. + Intent fileSelector = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  1883. + fileSelector.addCategory(Intent.CATEGORY_OPENABLE);
  1884. + fileSelector.setType("*/*");
  1885. + fileSelector.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  1886. +
  1887. + window.showIntent(fileSelector,
  1888. + new WindowAndroid.IntentCallback() {
  1889. + @Override
  1890. + public void onIntentCompleted(int resultCode, Intent data) {
  1891. + if (data == null) return;
  1892. + Uri filePath = data.getData();
  1893. + TryToInstall(context, filePath.toString());
  1894. + }
  1895. + },
  1896. + null);
  1897. + }
  1898. +
  1899. + public static void TryToInstall(Context context, String ScriptFullPath) {
  1900. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1901. + @Override
  1902. + public void onClick(DialogInterface dialog, int which) {
  1903. + switch (which){
  1904. + case DialogInterface.BUTTON_POSITIVE:
  1905. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1906. + break;
  1907. +
  1908. + case DialogInterface.BUTTON_NEGATIVE:
  1909. + break;
  1910. + }
  1911. + }
  1912. + };
  1913. +
  1914. + String scriptName = ScriptFullPath;
  1915. + if (ContentUriUtils.isContentUri(scriptName)) {
  1916. + scriptName = ContentUriUtils.getFilePathFromContentUri(Uri.parse(scriptName));
  1917. + if (scriptName == null) {
  1918. + // fallback to content uri name if fail
  1919. + scriptName = ContentUriUtils.getDisplayName(Uri.parse(ScriptFullPath), context,
  1920. + MediaStore.MediaColumns.DISPLAY_NAME);
  1921. + }
  1922. + }
  1923. +
  1924. + String message = context.getString(R.string.ask_to_install, scriptName);
  1925. +
  1926. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1927. + builder.setMessage(message)
  1928. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1929. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1930. + .show();
  1931. + }
  1932. +
  1933. + public static List<ScriptInfo> getUserScriptItems() {
  1934. + List<ScriptInfo> list = new ArrayList<>();
  1935. + try {
  1936. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1937. +
  1938. + JSONObject jsonObject = new JSONObject(json);
  1939. +
  1940. + JSONArray scripts = jsonObject.names();
  1941. + if (scripts != null) {
  1942. + Log.i(TAG, "User Scripts Loaded: %s", json);
  1943. + Log.i(TAG, "Totals scripts: %s", Integer.toString(scripts.length()));
  1944. + for (int i = 0; i < scripts.length(); i++) {
  1945. + String key = (String) scripts.get(i);
  1946. + JSONObject script = jsonObject.getJSONObject(key);
  1947. +
  1948. + ScriptInfo si = new ScriptInfo();
  1949. + si.Key = key;
  1950. + list.add(si);
  1951. +
  1952. + if(script.has("name")) si.Name = script.getString("name");
  1953. + if(script.has("description")) si.Description = script.getString("description");
  1954. + if(script.has("version")) si.Version = script.getString("version");
  1955. + if(script.has("file_path")) si.FilePath = script.getString("file_path");
  1956. + if(script.has("url_source")) si.UrlSource = script.getString("url_source");
  1957. + if(script.has("parser_error")) si.ParserError = script.getString("parser_error");
  1958. + if(script.has("force_disabled")) si.ForceDisabled = script.getBoolean("force_disabled");;
  1959. + si.Enabled = script.getBoolean("enabled");
  1960. + }
  1961. + } else {
  1962. + Log.i(TAG, "User Scripts list empty");
  1963. + }
  1964. + } catch (Exception e) {
  1965. + Log.e(TAG, "User Scripts Load Error", e.toString());
  1966. + }
  1967. + return list;
  1968. + }
  1969. +
  1970. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1971. + UserScriptsBridgeJni.get().registerLoadCallback();
  1972. + observer = new WeakReference<ScriptListPreference>(caller);
  1973. + }
  1974. +
  1975. + @CalledByNative
  1976. + private static void shouldRefreshUserScriptList() {
  1977. + ScriptListPreference reference = observer.get();
  1978. + if (reference != null) {
  1979. + reference.NotifyScriptsChanged();
  1980. + }
  1981. + }
  1982. +
  1983. + @CalledByNative
  1984. + private static void onUserScriptLoaded(boolean result, String error) {
  1985. + ScriptListPreference reference = observer.get();
  1986. + if (reference != null) {
  1987. + reference.OnUserScriptLoaded(result, error);
  1988. + }
  1989. + }
  1990. +
  1991. + @NativeMethods
  1992. + interface Natives {
  1993. + boolean isEnabled();
  1994. + void setEnabled(boolean enabled);
  1995. +
  1996. + String getScriptsInfo();
  1997. +
  1998. + void removeScript(String scriptKey);
  1999. + void setScriptEnabled(String scriptKey, boolean enabled);
  2000. +
  2001. + void reload();
  2002. + void selectAndAddScriptFromFile(WindowAndroid window);
  2003. + void tryToInstall(String scriptFullPath);
  2004. +
  2005. + void registerLoadCallback();
  2006. + }
  2007. +
  2008. +}
  2009. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  2010. new file mode 100755
  2011. --- /dev/null
  2012. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  2013. @@ -0,0 +1,116 @@
  2014. +/*
  2015. + This file is part of Bromite.
  2016. +
  2017. + Bromite is free software: you can redistribute it and/or modify
  2018. + it under the terms of the GNU General Public License as published by
  2019. + the Free Software Foundation, either version 3 of the License, or
  2020. + (at your option) any later version.
  2021. +
  2022. + Bromite is distributed in the hope that it will be useful,
  2023. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2024. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2025. + GNU General Public License for more details.
  2026. +
  2027. + You should have received a copy of the GNU General Public License
  2028. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2029. +*/
  2030. +
  2031. +package org.chromium.components.user_scripts;
  2032. +
  2033. +import android.app.Activity;
  2034. +import android.content.Context;
  2035. +import android.content.Intent;
  2036. +import android.os.Bundle;
  2037. +import android.provider.Browser;
  2038. +import android.net.Uri;
  2039. +import android.view.MenuItem;
  2040. +import android.view.View;
  2041. +
  2042. +import androidx.preference.Preference;
  2043. +import androidx.preference.PreferenceFragmentCompat;
  2044. +
  2045. +import org.chromium.base.Log;
  2046. +import org.chromium.ui.base.WindowAndroid;
  2047. +import org.chromium.ui.base.ActivityWindowAndroid;
  2048. +
  2049. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  2050. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  2051. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  2052. +
  2053. +import org.chromium.components.user_scripts.UserScriptsBridge;
  2054. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  2055. +
  2056. +public class UserScriptsPreferences
  2057. + extends PreferenceFragmentCompat
  2058. + implements SettingsUtils.ISupportHelpAndFeedback {
  2059. +
  2060. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  2061. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  2062. +
  2063. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  2064. +
  2065. + private FragmentWindowAndroid mWindowAndroid;
  2066. +
  2067. + @Override
  2068. + public void onDestroy() {
  2069. + if (mWindowAndroid != null) mWindowAndroid.destroy();
  2070. + super.onDestroy();
  2071. + }
  2072. +
  2073. + @Override
  2074. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  2075. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  2076. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  2077. +
  2078. + ChromeSwitchPreference enabledSwitch =
  2079. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  2080. + ScriptListPreference listPreference =
  2081. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  2082. +
  2083. + boolean enabled = UserScriptsBridge.isEnabled();
  2084. + enabledSwitch.setChecked(enabled);
  2085. + listPreference.setEnabled(enabled);
  2086. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  2087. + UserScriptsBridge.setEnabled((boolean) newValue);
  2088. + listPreference.setEnabled((boolean) newValue);
  2089. + return true;
  2090. + });
  2091. +
  2092. + mWindowAndroid = new FragmentWindowAndroid(getContext(), this);
  2093. + listPreference.setWindowAndroid(mWindowAndroid);
  2094. + }
  2095. +
  2096. + @Override
  2097. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  2098. + // handle picker callback from SelectFileDialog
  2099. + mWindowAndroid.getIntentRequestTracker().onActivityResult(requestCode, resultCode, data);
  2100. + }
  2101. +
  2102. + public void onHelpAndFeebackPressed() {
  2103. + Context context = getContext();
  2104. +
  2105. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  2106. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  2107. + // the user presses 'back' button.
  2108. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  2109. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  2110. + intent.setPackage(context.getPackageName());
  2111. + context.startActivity(intent);
  2112. + }
  2113. +
  2114. + public static Bundle createFragmentArgsForInstall(String filePath) {
  2115. + Bundle fragmentArgs = new Bundle();
  2116. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  2117. + return fragmentArgs;
  2118. + }
  2119. +
  2120. + @Override
  2121. + public void onActivityCreated(Bundle savedInstanceState) {
  2122. + super.onActivityCreated(savedInstanceState);
  2123. +
  2124. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  2125. + if (scriptToInstall != null) {
  2126. + UserScriptsBridge.TryToInstall(getContext(), scriptToInstall);
  2127. + }
  2128. + }
  2129. +}
  2130. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  2131. new file mode 100644
  2132. --- /dev/null
  2133. +++ b/components/user_scripts/android/java_sources.gni
  2134. @@ -0,0 +1,18 @@
  2135. +# This file is part of Bromite.
  2136. +
  2137. +# Bromite is free software: you can redistribute it and/or modify
  2138. +# it under the terms of the GNU General Public License as published by
  2139. +# the Free Software Foundation, either version 3 of the License, or
  2140. +# (at your option) any later version.
  2141. +
  2142. +# Bromite is distributed in the hope that it will be useful,
  2143. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2144. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2145. +# GNU General Public License for more details.
  2146. +
  2147. +# You should have received a copy of the GNU General Public License
  2148. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2149. +
  2150. +userscripts_java_sources = [
  2151. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  2152. +]
  2153. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  2154. new file mode 100644
  2155. --- /dev/null
  2156. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  2157. @@ -0,0 +1,173 @@
  2158. +/*
  2159. + This file is part of Bromite.
  2160. +
  2161. + Bromite is free software: you can redistribute it and/or modify
  2162. + it under the terms of the GNU General Public License as published by
  2163. + the Free Software Foundation, either version 3 of the License, or
  2164. + (at your option) any later version.
  2165. +
  2166. + Bromite is distributed in the hope that it will be useful,
  2167. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2168. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2169. + GNU General Public License for more details.
  2170. +
  2171. + You should have received a copy of the GNU General Public License
  2172. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2173. +*/
  2174. +
  2175. +#include <jni.h>
  2176. +#include <algorithm>
  2177. +#include <string>
  2178. +#include <vector>
  2179. +#include <sstream>
  2180. +#include <iterator>
  2181. +
  2182. +#include "base/android/callback_android.h"
  2183. +#include "base/android/jni_android.h"
  2184. +#include "base/android/jni_array.h"
  2185. +#include "base/android/jni_string.h"
  2186. +#include "base/android/scoped_java_ref.h"
  2187. +#include "ui/android/window_android.h"
  2188. +
  2189. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  2190. +#include "../browser/userscripts_browser_client.h"
  2191. +#include "user_scripts_bridge.h"
  2192. +
  2193. +using base::android::AttachCurrentThread;
  2194. +using base::android::ConvertJavaStringToUTF8;
  2195. +using base::android::ConvertUTF16ToJavaString;
  2196. +using base::android::ConvertUTF8ToJavaString;
  2197. +using base::android::JavaParamRef;
  2198. +using base::android::JavaRef;
  2199. +using base::android::ScopedJavaGlobalRef;
  2200. +using base::android::ScopedJavaLocalRef;
  2201. +using content::BrowserContext;
  2202. +
  2203. +namespace {
  2204. +
  2205. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  2206. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  2207. +}
  2208. +
  2209. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  2210. + private:
  2211. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  2212. + content::BrowserContext* browser_context) override {
  2213. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  2214. + }
  2215. +
  2216. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  2217. + bool result, const std::string& error) override {
  2218. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  2219. + result, error);
  2220. + }
  2221. +
  2222. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  2223. +};
  2224. +
  2225. +CallbackObserver* g_userscripts_loader_observer = NULL;
  2226. +
  2227. +}
  2228. +
  2229. +namespace user_scripts {
  2230. +
  2231. +static jboolean JNI_UserScriptsBridge_IsEnabled(
  2232. + JNIEnv* env) {
  2233. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2234. + if (client == NULL) return false;
  2235. + return client->GetPrefs()->IsEnabled();
  2236. +}
  2237. +
  2238. +static void JNI_UserScriptsBridge_SetEnabled(
  2239. + JNIEnv* env,
  2240. + jboolean is_enabled) {
  2241. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2242. + if (client == NULL) return;
  2243. + client->GetPrefs()->SetEnabled(is_enabled);
  2244. + client->GetLoader()->StartLoad();
  2245. +}
  2246. +
  2247. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  2248. + JNIEnv* env) {
  2249. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2250. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  2251. +
  2252. + std::string json = client->GetPrefs()->GetScriptsInfo();
  2253. + return ConvertUTF8ToJavaString(env, json);
  2254. +}
  2255. +
  2256. +static void JNI_UserScriptsBridge_RemoveScript(
  2257. + JNIEnv* env,
  2258. + const JavaParamRef<jstring>& jscript_key) {
  2259. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2260. + if (client == NULL) return;
  2261. +
  2262. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2263. + client->GetLoader()->RemoveScript(script_key);
  2264. +}
  2265. +
  2266. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  2267. + JNIEnv* env,
  2268. + const JavaParamRef<jstring>& jscript_key,
  2269. + jboolean is_enabled) {
  2270. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2271. + if (client == NULL) return;
  2272. +
  2273. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2274. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  2275. +}
  2276. +
  2277. +static void JNI_UserScriptsBridge_Reload(
  2278. + JNIEnv* env) {
  2279. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2280. + if (client == NULL) return;
  2281. +
  2282. + client->GetLoader()->StartLoad();
  2283. + user_scripts::ShouldRefreshUserScriptList(env);
  2284. +}
  2285. +
  2286. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  2287. + JNIEnv* env,
  2288. + const JavaParamRef<jobject>& jwindow_android) {
  2289. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2290. + if (client == NULL) return;
  2291. +
  2292. + client->GetLoader()->SelectAndAddScriptFromFile(
  2293. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  2294. +}
  2295. +
  2296. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  2297. + const JavaParamRef<jstring>& jscript_path) {
  2298. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2299. + if (client == NULL) return;
  2300. +
  2301. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  2302. + base::FilePath path(script_path);
  2303. +
  2304. + client->GetLoader()->TryToInstall(path);
  2305. +}
  2306. +
  2307. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  2308. + JNIEnv* env) {
  2309. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2310. + if (client == NULL) return;
  2311. +
  2312. + if (g_userscripts_loader_observer == NULL) {
  2313. + g_userscripts_loader_observer = new CallbackObserver();
  2314. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  2315. + }
  2316. +}
  2317. +
  2318. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  2319. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  2320. +}
  2321. +
  2322. +static void OnUserScriptLoaded(JNIEnv* env,
  2323. + bool result, const std::string& error) {
  2324. + base::android::ScopedJavaLocalRef<jstring> j_error =
  2325. + base::android::ConvertUTF8ToJavaString(env, error);
  2326. +
  2327. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  2328. +}
  2329. +
  2330. +}
  2331. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  2332. new file mode 100644
  2333. --- /dev/null
  2334. +++ b/components/user_scripts/android/user_scripts_bridge.h
  2335. @@ -0,0 +1,31 @@
  2336. +/*
  2337. + This file is part of Bromite.
  2338. +
  2339. + Bromite is free software: you can redistribute it and/or modify
  2340. + it under the terms of the GNU General Public License as published by
  2341. + the Free Software Foundation, either version 3 of the License, or
  2342. + (at your option) any later version.
  2343. +
  2344. + Bromite is distributed in the hope that it will be useful,
  2345. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2346. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2347. + GNU General Public License for more details.
  2348. +
  2349. + You should have received a copy of the GNU General Public License
  2350. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2351. +*/
  2352. +
  2353. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2354. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2355. +
  2356. +#include <jni.h>
  2357. +
  2358. +namespace user_scripts {
  2359. +
  2360. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  2361. +static void OnUserScriptLoaded(JNIEnv* env,
  2362. + bool result, const std::string& error);
  2363. +
  2364. +} // namespace user_scripts
  2365. +
  2366. +#endif
  2367. \ No newline at end of file
  2368. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  2369. new file mode 100755
  2370. --- /dev/null
  2371. +++ b/components/user_scripts/browser/BUILD.gn
  2372. @@ -0,0 +1,81 @@
  2373. +# This file is part of Bromite.
  2374. +
  2375. +# Bromite is free software: you can redistribute it and/or modify
  2376. +# it under the terms of the GNU General Public License as published by
  2377. +# the Free Software Foundation, either version 3 of the License, or
  2378. +# (at your option) any later version.
  2379. +
  2380. +# Bromite is distributed in the hope that it will be useful,
  2381. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2382. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2383. +# GNU General Public License for more details.
  2384. +
  2385. +# You should have received a copy of the GNU General Public License
  2386. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2387. +
  2388. +import("//build/config/features.gni")
  2389. +import("//tools/grit/grit_rule.gni")
  2390. +
  2391. +group("browser") {
  2392. + public_deps = [
  2393. + "//components/user_scripts/browser:browser_sources",
  2394. + ]
  2395. +}
  2396. +
  2397. +source_set("browser_sources") {
  2398. + visibility = [ "./*" ]
  2399. +
  2400. + sources = [
  2401. + "file_task_runner.cc",
  2402. + "file_task_runner.h",
  2403. + "userscripts_browser_client.cc",
  2404. + "userscripts_browser_client.h",
  2405. + "user_script_loader.cc",
  2406. + "user_script_loader.h",
  2407. + "user_script_prefs.cc",
  2408. + "user_script_prefs.h",
  2409. + "user_script_pref_info.cc",
  2410. + "user_script_pref_info.h",
  2411. + "ui/user_scripts_ui.h",
  2412. + "ui/user_scripts_ui.cc",
  2413. + ]
  2414. +
  2415. + deps = [
  2416. + ":userscripts_browser_resources",
  2417. + "//base:i18n",
  2418. + "//components/keyed_service/content",
  2419. + "//components/keyed_service/core",
  2420. + "//components/pref_registry",
  2421. + "//components/prefs",
  2422. + "//content/public/browser",
  2423. + "//components/user_scripts/common",
  2424. + "//services/device/public/mojom",
  2425. + "//services/preferences/public/cpp",
  2426. + "//services/service_manager/public/cpp",
  2427. + "//third_party/blink/public/common",
  2428. + "//ui/display",
  2429. + ]
  2430. +
  2431. + public_deps = [
  2432. + "//content/public/common",
  2433. + ]
  2434. +
  2435. + configs += [
  2436. + "//build/config:precompiled_headers",
  2437. + "//build/config/compiler:wexit_time_destructors",
  2438. + ]
  2439. +}
  2440. +
  2441. +group("closure_compile") {
  2442. + deps = [ "resources/user-script-ui:closure_compile" ]
  2443. +}
  2444. +
  2445. +grit("userscripts_browser_resources") {
  2446. + source = "resources/browser_resources.grd"
  2447. +
  2448. + output_dir = "$root_gen_dir/chrome"
  2449. + outputs = [
  2450. + "grit/userscripts_browser_resources.h",
  2451. + "userscripts_browser_resources.pak",
  2452. + ]
  2453. +}
  2454. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2455. new file mode 100755
  2456. --- /dev/null
  2457. +++ b/components/user_scripts/browser/file_task_runner.cc
  2458. @@ -0,0 +1,40 @@
  2459. +/*
  2460. + This file is part of Bromite.
  2461. +
  2462. + Bromite is free software: you can redistribute it and/or modify
  2463. + it under the terms of the GNU General Public License as published by
  2464. + the Free Software Foundation, either version 3 of the License, or
  2465. + (at your option) any later version.
  2466. +
  2467. + Bromite is distributed in the hope that it will be useful,
  2468. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2469. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2470. + GNU General Public License for more details.
  2471. +
  2472. + You should have received a copy of the GNU General Public License
  2473. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2474. +*/
  2475. +
  2476. +#include "file_task_runner.h"
  2477. +
  2478. +#include "base/task/sequenced_task_runner.h"
  2479. +#include "base/task/lazy_thread_pool_task_runner.h"
  2480. +#include "base/task/task_traits.h"
  2481. +
  2482. +namespace user_scripts {
  2483. +
  2484. +namespace {
  2485. +
  2486. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2487. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2488. + base::TaskTraits(base::MayBlock(),
  2489. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2490. + base::TaskPriority::USER_VISIBLE));
  2491. +
  2492. +} // namespace
  2493. +
  2494. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2495. + return g_us_task_runner.Get();
  2496. +}
  2497. +
  2498. +} // namespace user_scripts
  2499. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2500. new file mode 100755
  2501. --- /dev/null
  2502. +++ b/components/user_scripts/browser/file_task_runner.h
  2503. @@ -0,0 +1,34 @@
  2504. +/*
  2505. + This file is part of Bromite.
  2506. +
  2507. + Bromite is free software: you can redistribute it and/or modify
  2508. + it under the terms of the GNU General Public License as published by
  2509. + the Free Software Foundation, either version 3 of the License, or
  2510. + (at your option) any later version.
  2511. +
  2512. + Bromite is distributed in the hope that it will be useful,
  2513. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2514. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2515. + GNU General Public License for more details.
  2516. +
  2517. + You should have received a copy of the GNU General Public License
  2518. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2519. +*/
  2520. +
  2521. +#ifndef USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2522. +#define USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2523. +
  2524. +#include "base/memory/ref_counted.h"
  2525. +#include "base/task/task_traits.h"
  2526. +
  2527. +namespace base {
  2528. +class SequencedTaskRunner;
  2529. +}
  2530. +
  2531. +namespace user_scripts {
  2532. +
  2533. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2534. +
  2535. +} // namespace extensions
  2536. +
  2537. +#endif // USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2538. diff --git a/components/user_scripts/browser/resources/browser_resources.grd b/components/user_scripts/browser/resources/browser_resources.grd
  2539. new file mode 100644
  2540. --- /dev/null
  2541. +++ b/components/user_scripts/browser/resources/browser_resources.grd
  2542. @@ -0,0 +1,14 @@
  2543. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  2544. + <outputs>
  2545. + <output filename="grit/userscripts_browser_resources.h" type="rc_header">
  2546. + <emit emit_type='prepend'></emit>
  2547. + </output>
  2548. + <output filename="userscripts_browser_resources.pak" type="data_package" />
  2549. + </outputs>
  2550. + <release seq="1">
  2551. + <includes>
  2552. + <include name="IDR_USER_SCRIPTS_HTML" file="user-script-ui\user-scripts-ui.html" type="BINDATA" />
  2553. + <include name="IDR_USER_SCRIPTS_JS" file="user-script-ui\user-scripts-ui.js" type="BINDATA" />
  2554. + </includes>
  2555. + </release>
  2556. +</grit>
  2557. \ No newline at end of file
  2558. diff --git a/components/user_scripts/browser/resources/user-script-ui/BUILD.gn b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2559. new file mode 100644
  2560. --- /dev/null
  2561. +++ b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2562. @@ -0,0 +1,12 @@
  2563. +import("//third_party/closure_compiler/compile_js.gni")
  2564. +
  2565. +js_type_check("closure_compile") {
  2566. + deps = [ ":view_script_source" ]
  2567. +}
  2568. +
  2569. +js_library("view_script_source") {
  2570. + deps = [
  2571. + "//ui/webui/resources/js:cr.m",
  2572. + "//ui/webui/resources/js:util.m",
  2573. + ]
  2574. +}
  2575. \ No newline at end of file
  2576. diff --git a/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2577. new file mode 100644
  2578. --- /dev/null
  2579. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2580. @@ -0,0 +1,14 @@
  2581. +<!doctype html>
  2582. +<html lang="en">
  2583. +<head>
  2584. + <meta charset="utf-8">
  2585. + <title>Local State Debug Page</title>
  2586. + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  2587. + <script type="module" src="user-scripts-ui.js"></script>
  2588. +</head>
  2589. +<body>
  2590. + <pre id="content">
  2591. + Loading Script Source file...
  2592. + </pre>
  2593. +</body>
  2594. +</html>
  2595. \ No newline at end of file
  2596. diff --git a/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2597. new file mode 100644
  2598. --- /dev/null
  2599. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2600. @@ -0,0 +1,9 @@
  2601. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
  2602. +import {$} from 'chrome://resources/js/util.m.js';
  2603. +
  2604. +document.addEventListener('DOMContentLoaded', function() {
  2605. + const urlParams = new URLSearchParams(window.location.search);
  2606. + sendWithPromise('requestSource', urlParams.get('key')).then(textContent => {
  2607. + $('content').textContent = textContent[0].content;
  2608. + });
  2609. +});
  2610. \ No newline at end of file
  2611. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.cc b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2612. new file mode 100644
  2613. --- /dev/null
  2614. +++ b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2615. @@ -0,0 +1,147 @@
  2616. +/*
  2617. + This file is part of Bromite.
  2618. +
  2619. + Bromite is free software: you can redistribute it and/or modify
  2620. + it under the terms of the GNU General Public License as published by
  2621. + the Free Software Foundation, either version 3 of the License, or
  2622. + (at your option) any later version.
  2623. +
  2624. + Bromite is distributed in the hope that it will be useful,
  2625. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2626. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2627. + GNU General Public License for more details.
  2628. +
  2629. + You should have received a copy of the GNU General Public License
  2630. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2631. +*/
  2632. +
  2633. +
  2634. +#include <memory>
  2635. +
  2636. +#include "base/bind.h"
  2637. +#include "base/json/json_string_value_serializer.h"
  2638. +#include "base/memory/writable_shared_memory_region.h"
  2639. +#include "base/strings/string_util.h"
  2640. +#include "base/values.h"
  2641. +
  2642. +#include "chrome/browser/browser_process.h"
  2643. +#include "chrome/browser/profiles/profile.h"
  2644. +#include "chrome/common/url_constants.h"
  2645. +#include "chrome/grit/userscripts_browser_resources.h"
  2646. +#include "components/prefs/pref_service.h"
  2647. +#include "content/public/browser/web_ui.h"
  2648. +#include "content/public/browser/web_ui_controller.h"
  2649. +#include "content/public/browser/web_ui_data_source.h"
  2650. +#include "content/public/browser/web_ui_message_handler.h"
  2651. +
  2652. +#include "user_scripts_ui.h"
  2653. +#include "../userscripts_browser_client.h"
  2654. +#include "../../common/user_script.h"
  2655. +
  2656. +namespace {
  2657. +
  2658. +class UserScriptsUIHandler : public content::WebUIMessageHandler {
  2659. + public:
  2660. + UserScriptsUIHandler(const UserScriptsUIHandler&) = delete;
  2661. + UserScriptsUIHandler& operator=(const UserScriptsUIHandler&) = delete;
  2662. + UserScriptsUIHandler();
  2663. + ~UserScriptsUIHandler() override;
  2664. +
  2665. + // content::WebUIMessageHandler:
  2666. + void RegisterMessages() override;
  2667. +
  2668. + private:
  2669. + void HandleRequestSource(const base::Value::List& args);
  2670. + void OnScriptsLoaded(
  2671. + const std::string callback_id,
  2672. + const std::string script_key,
  2673. + std::unique_ptr<user_scripts::UserScriptList> user_scripts);
  2674. +
  2675. + std::unique_ptr<user_scripts::UserScriptList> loaded_scripts_;
  2676. +
  2677. + base::WeakPtrFactory<UserScriptsUIHandler> weak_factory_{this};
  2678. +};
  2679. +
  2680. +UserScriptsUIHandler::UserScriptsUIHandler()
  2681. + : loaded_scripts_(new user_scripts::UserScriptList()) {
  2682. +}
  2683. +
  2684. +UserScriptsUIHandler::~UserScriptsUIHandler() {
  2685. +}
  2686. +
  2687. +void UserScriptsUIHandler::RegisterMessages() {
  2688. + web_ui()->RegisterMessageCallback(
  2689. + "requestSource",
  2690. + base::BindRepeating(&UserScriptsUIHandler::HandleRequestSource,
  2691. + base::Unretained(this)));
  2692. +}
  2693. +
  2694. +void UserScriptsUIHandler::HandleRequestSource(const base::Value::List& args) {
  2695. + AllowJavascript();
  2696. + if (args.size() < 2) return;
  2697. +
  2698. + std::string callback_id = args[0].GetString();
  2699. + std::string script_key = args[1].GetString();
  2700. + if (script_key.empty()) {
  2701. + std::string json = "Missing key value.";
  2702. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2703. + return;
  2704. + }
  2705. +
  2706. + user_scripts::UserScriptsBrowserClient* client = user_scripts::UserScriptsBrowserClient::GetInstance();
  2707. + if (client == NULL) {
  2708. + std::string json = "User scripts disabled.";
  2709. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2710. + } else {
  2711. + std::unique_ptr<user_scripts::UserScriptList> scripts_to_load =
  2712. + std::move(loaded_scripts_);
  2713. + scripts_to_load->clear();
  2714. +
  2715. + client->GetLoader()->LoadScripts(std::move(scripts_to_load),
  2716. + base::BindOnce(
  2717. + &UserScriptsUIHandler::OnScriptsLoaded,
  2718. + weak_factory_.GetWeakPtr(),
  2719. + callback_id, script_key)
  2720. + );
  2721. + }
  2722. +}
  2723. +
  2724. +void UserScriptsUIHandler::OnScriptsLoaded(
  2725. + const std::string callback_id,
  2726. + const std::string script_key,
  2727. + std::unique_ptr<user_scripts::UserScriptList> user_scripts) {
  2728. + loaded_scripts_ = std::move(user_scripts);
  2729. +
  2730. + base::ListValue response;
  2731. + for (const std::unique_ptr<user_scripts::UserScript>& script : *loaded_scripts_) {
  2732. + if (script->key() == script_key) {
  2733. + base::Value::Dict scriptData;
  2734. + for (const std::unique_ptr<user_scripts::UserScript::File>& js_file :
  2735. + script->js_scripts()) {
  2736. + base::StringPiece contents = js_file->GetContent();
  2737. + scriptData.Set("content", contents.data());
  2738. + }
  2739. + response.Append(std::move(scriptData));
  2740. + }
  2741. + }
  2742. +
  2743. + ResolveJavascriptCallback(base::Value(callback_id), response);
  2744. +}
  2745. +
  2746. +} // namespace
  2747. +
  2748. +namespace user_scripts {
  2749. +
  2750. +UserScriptsUI::UserScriptsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  2751. + content::WebUIDataSource* html_source =
  2752. + content::WebUIDataSource::Create(kChromeUIUserScriptsHost);
  2753. + html_source->SetDefaultResource(IDR_USER_SCRIPTS_HTML);
  2754. + html_source->AddResourcePath("user-scripts-ui.js", IDR_USER_SCRIPTS_JS);
  2755. + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
  2756. + web_ui->AddMessageHandler(std::make_unique<UserScriptsUIHandler>());
  2757. +}
  2758. +
  2759. +UserScriptsUI::~UserScriptsUI() {
  2760. +}
  2761. +
  2762. +}
  2763. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.h b/components/user_scripts/browser/ui/user_scripts_ui.h
  2764. new file mode 100644
  2765. --- /dev/null
  2766. +++ b/components/user_scripts/browser/ui/user_scripts_ui.h
  2767. @@ -0,0 +1,37 @@
  2768. +/*
  2769. + This file is part of Bromite.
  2770. +
  2771. + Bromite is free software: you can redistribute it and/or modify
  2772. + it under the terms of the GNU General Public License as published by
  2773. + the Free Software Foundation, either version 3 of the License, or
  2774. + (at your option) any later version.
  2775. +
  2776. + Bromite is distributed in the hope that it will be useful,
  2777. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2778. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2779. + GNU General Public License for more details.
  2780. +
  2781. + You should have received a copy of the GNU General Public License
  2782. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2783. +*/
  2784. +
  2785. +#ifndef USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2786. +#define USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2787. +
  2788. +#include "content/public/browser/web_ui_controller.h"
  2789. +
  2790. +namespace user_scripts {
  2791. +
  2792. +const char kChromeUIUserScriptsHost[] = "user-scripts";
  2793. +
  2794. +class UserScriptsUI : public content::WebUIController {
  2795. + public:
  2796. + UserScriptsUI(const UserScriptsUI&) = delete;
  2797. + UserScriptsUI& operator=(const UserScriptsUI&) = delete;
  2798. + explicit UserScriptsUI(content::WebUI* web_ui);
  2799. + ~UserScriptsUI() override;
  2800. +};
  2801. +
  2802. +}
  2803. +
  2804. +#endif
  2805. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2806. new file mode 100755
  2807. --- /dev/null
  2808. +++ b/components/user_scripts/browser/user_script_loader.cc
  2809. @@ -0,0 +1,716 @@
  2810. +/*
  2811. + This file is part of Bromite.
  2812. +
  2813. + Bromite is free software: you can redistribute it and/or modify
  2814. + it under the terms of the GNU General Public License as published by
  2815. + the Free Software Foundation, either version 3 of the License, or
  2816. + (at your option) any later version.
  2817. +
  2818. + Bromite is distributed in the hope that it will be useful,
  2819. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2820. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2821. + GNU General Public License for more details.
  2822. +
  2823. + You should have received a copy of the GNU General Public License
  2824. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2825. +*/
  2826. +
  2827. +#include "user_script_loader.h"
  2828. +
  2829. +#include <stddef.h>
  2830. +
  2831. +#include <set>
  2832. +#include <string>
  2833. +#include <utility>
  2834. +
  2835. +#include "base/bind.h"
  2836. +#include "base/memory/writable_shared_memory_region.h"
  2837. +#include "base/strings/string_util.h"
  2838. +#include "base/strings/strcat.h"
  2839. +#include "base/files/file.h"
  2840. +#include "base/files/file_util.h"
  2841. +#include "base/files/file_enumerator.h"
  2842. +#include "base/i18n/file_util_icu.h"
  2843. +#include "base/path_service.h"
  2844. +#include "base/base_paths_android.h"
  2845. +#include "base/strings/utf_string_conversions.h"
  2846. +#include "base/android/content_uri_utils.h"
  2847. +#include "base/android/jni_android.h"
  2848. +#include "base/task/task_traits.h"
  2849. +#include "base/version.h"
  2850. +
  2851. +#include "crypto/sha2.h"
  2852. +#include "base/base64.h"
  2853. +
  2854. +#include "build/build_config.h"
  2855. +#include "content/public/browser/browser_context.h"
  2856. +#include "content/public/browser/browser_task_traits.h"
  2857. +#include "content/public/browser/browser_thread.h"
  2858. +#include "content/public/browser/notification_service.h"
  2859. +#include "content/public/browser/notification_types.h"
  2860. +#include "content/public/browser/render_process_host.h"
  2861. +#include "ui/shell_dialogs/select_file_dialog.h"
  2862. +#include "content/browser/file_system_access/file_system_chooser.h"
  2863. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2864. +#include "ui/android/window_android.h"
  2865. +
  2866. +#include "../common/user_scripts_features.h"
  2867. +#include "../common/extension_messages.h"
  2868. +#include "file_task_runner.h"
  2869. +#include "user_script_prefs.h"
  2870. +#include "user_script_pref_info.h"
  2871. +#include "../common/host_id.h"
  2872. +
  2873. +using content::BrowserThread;
  2874. +using content::BrowserContext;
  2875. +
  2876. +namespace user_scripts {
  2877. +
  2878. +namespace {
  2879. +
  2880. +static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2881. +static const base::StringPiece kUserScriptEnd("// ==/UserScript==");
  2882. +static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2883. +static const base::StringPiece kNameDeclaration("// @name");
  2884. +static const base::StringPiece kVersionDeclaration("// @version");
  2885. +static const base::StringPiece kDescriptionDeclaration("// @description");
  2886. +static const base::StringPiece kIncludeDeclaration("// @include");
  2887. +static const base::StringPiece kExcludeDeclaration("// @exclude");
  2888. +static const base::StringPiece kMatchDeclaration("// @match");
  2889. +static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2890. +static const base::StringPiece kRunAtDeclaration("// @run-at");
  2891. +static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2892. +static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2893. +static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2894. +static const base::StringPiece kUrlSourceDeclaration("// @url");
  2895. +static const base::StringPiece kUrlHomePageDeclaration("// @homepage");
  2896. +
  2897. +// internal use
  2898. +static const base::StringPiece kParserError("// @error");
  2899. +static const base::StringPiece kForceDisabled("// @disabled");
  2900. +
  2901. +// Helper function to parse greasesmonkey headers
  2902. +bool GetDeclarationValue(const base::StringPiece& line,
  2903. + const base::StringPiece& prefix,
  2904. + std::string* value) {
  2905. + base::StringPiece::size_type index = line.find(prefix);
  2906. + if (index == base::StringPiece::npos)
  2907. + return false;
  2908. +
  2909. + std::string temp(line.data() + index + prefix.length(),
  2910. + line.length() - index - prefix.length());
  2911. +
  2912. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2913. + return false;
  2914. +
  2915. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2916. + return true;
  2917. +}
  2918. +
  2919. +} // namespace
  2920. +
  2921. +// static
  2922. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2923. + std::unique_ptr<UserScript>& script,
  2924. + bool *found_metadata,
  2925. + std::string& error_message) {
  2926. + // http://wiki.greasespot.net/Metadata_block
  2927. + base::StringPiece line;
  2928. + size_t line_start = 0;
  2929. + size_t line_end = line_start;
  2930. + *found_metadata = false;
  2931. +
  2932. + while (line_start < script_text.length()) {
  2933. + line_end = script_text.find('\n', line_start);
  2934. +
  2935. + // Handle the case where there is no trailing newline in the file.
  2936. + if (line_end == std::string::npos)
  2937. + line_end = script_text.length() - 1;
  2938. +
  2939. + line = base::StringPiece(script_text.data() + line_start,
  2940. + line_end - line_start);
  2941. +
  2942. + if (!*found_metadata) {
  2943. + if (base::StartsWith(line, kUserScriptBegin))
  2944. + *found_metadata = true;
  2945. + } else {
  2946. + if (base::StartsWith(line, kUserScriptEnd))
  2947. + break;
  2948. +
  2949. + std::string value;
  2950. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2951. + // We escape some characters that MatchPattern() considers special.
  2952. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2953. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2954. + script->add_glob(value);
  2955. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2956. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2957. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2958. + script->add_exclude_glob(value);
  2959. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2960. + script->set_name_space(value);
  2961. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2962. + script->set_name(value);
  2963. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2964. + base::Version version(value);
  2965. + if (version.IsValid())
  2966. + script->set_version(version.GetString());
  2967. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  2968. + script->set_description(value);
  2969. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  2970. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  2971. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  2972. + error_message = "Invalid UserScript Schema " + value;
  2973. + return false;
  2974. + }
  2975. + script->add_url_pattern(pattern);
  2976. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  2977. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  2978. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  2979. + error_message = "Invalid UserScript Schema " + value;
  2980. + return false;
  2981. + }
  2982. + script->add_exclude_url_pattern(exclude);
  2983. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  2984. + if (value == kRunAtDocumentStartValue)
  2985. + script->set_run_location(UserScript::DOCUMENT_START);
  2986. + else if (value == kRunAtDocumentEndValue)
  2987. + script->set_run_location(UserScript::DOCUMENT_END);
  2988. + else if (value == kRunAtDocumentIdleValue)
  2989. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  2990. + else {
  2991. + error_message = "Invalid RunAtDeclaration " + value;
  2992. + return false;
  2993. + }
  2994. + } else if (GetDeclarationValue(line, kUrlSourceDeclaration, &value) ||
  2995. + GetDeclarationValue(line, kUrlHomePageDeclaration, &value)) {
  2996. + script->set_url_source(value);
  2997. + } else if (GetDeclarationValue(line, kParserError, &value)) {
  2998. + script->set_parser_error(value);
  2999. + } else if (GetDeclarationValue(line, kForceDisabled, &value)) {
  3000. + script->set_force_disabled();
  3001. + }
  3002. +
  3003. + // TODO(aa): Handle more types of metadata.
  3004. + }
  3005. +
  3006. + line_start = line_end + 1;
  3007. + }
  3008. +
  3009. + // If no patterns were specified, default to @include *. This is what
  3010. + // Greasemonkey does.
  3011. + if (script->globs().empty() && script->url_patterns().is_empty())
  3012. + script->add_glob("*");
  3013. +
  3014. + return true;
  3015. +}
  3016. +
  3017. +// static
  3018. +bool LoadUserScriptFromFile(
  3019. + const base::FilePath& user_script_path, const GURL& original_url,
  3020. + std::unique_ptr<UserScript>& script,
  3021. + bool* found_metadata,
  3022. + std::u16string* error) {
  3023. +
  3024. + base::File infile;
  3025. + if (user_script_path.IsContentUri()) {
  3026. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3027. + LOG(INFO) << "UserScriptLoader: path " << user_script_path << " is a content uri";
  3028. +
  3029. + infile = OpenContentUriForRead(user_script_path);
  3030. + } else {
  3031. + infile = base::File(user_script_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  3032. + }
  3033. +
  3034. + if (!infile.IsValid()) {
  3035. + base::File::Error out_error = infile.error_details();
  3036. + *error = u"Cannot open script source. Error: " +
  3037. + base::ASCIIToUTF16(base::File::ErrorToString(out_error));
  3038. + return false;
  3039. + }
  3040. +
  3041. + auto length = infile.GetLength();
  3042. + if (length<=0) {
  3043. + *error = u"File is empty.";
  3044. + return false;
  3045. + }
  3046. +
  3047. + auto buffer = std::vector<char>(length);
  3048. + int bytes_read = infile.Read(0, buffer.data(), length);
  3049. + if (bytes_read == -1) {
  3050. + *error = u"Could not read source file.";
  3051. + return false;
  3052. + }
  3053. +
  3054. + std::string content(buffer.begin(), buffer.end());
  3055. + if (!base::IsStringUTF8(content)) {
  3056. + *error = u"User script must be UTF8 encoded.";
  3057. + return false;
  3058. + }
  3059. +
  3060. + std::string detailed_error;
  3061. + bool parseResult = UserScriptLoader::ParseMetadataHeader(content, script,
  3062. + found_metadata, detailed_error);
  3063. + if (parseResult == false || *found_metadata == false) {
  3064. + std::u16string detailed_error16;
  3065. + base::UTF8ToUTF16(detailed_error.c_str(), detailed_error.length(), &detailed_error16);
  3066. + *error = base::StrCat({u"Invalid script header. ", detailed_error16});
  3067. + return false;
  3068. + }
  3069. +
  3070. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  3071. +
  3072. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  3073. + file->set_content(content);
  3074. +
  3075. + // create SHA256 of file
  3076. + char raw[crypto::kSHA256Length] = {0};
  3077. + std::string key;
  3078. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  3079. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  3080. + file->set_key(key);
  3081. +
  3082. + file->set_url(GURL(base::StrCat({"https://userscripts/file/", key, ".js"})));
  3083. +
  3084. + script->js_scripts().push_back(std::move(file));
  3085. +
  3086. + // add into key the filename
  3087. + // this value is used in ui to discriminate scripts
  3088. + script->set_key(user_script_path.BaseName().value());
  3089. + return true;
  3090. +}
  3091. +
  3092. +// static
  3093. +bool GetOrCreatePath(base::FilePath& path) {
  3094. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  3095. + path = path.AppendASCII("userscripts");
  3096. +
  3097. + // create snippets directory if not exists
  3098. + if (!base::PathExists(path)) {
  3099. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  3100. + base::File::Error error = base::File::FILE_OK;
  3101. + if (!base::CreateDirectoryAndGetError(path, &error)) {
  3102. + LOG(ERROR) <<
  3103. + "UserScriptLoader: failed to create directory: " << path
  3104. + << " with error code " << error;
  3105. + return false;
  3106. + }
  3107. + }
  3108. + return true;
  3109. +}
  3110. +
  3111. +// static
  3112. +void LoadUserScripts(UserScriptList* user_scripts_list) {
  3113. + base::FilePath path;
  3114. + if (GetOrCreatePath(path) == false) return;
  3115. +
  3116. + // enumerate all files from script path
  3117. + // we accept all files, but we check if it's a real
  3118. + // userscript
  3119. + base::FileEnumerator dir_enum(
  3120. + path,
  3121. + /*recursive=*/false, base::FileEnumerator::FILES);
  3122. + base::FilePath full_name;
  3123. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  3124. + std::unique_ptr<UserScript> userscript(new UserScript());
  3125. + userscript->set_id(UserScript::GenerateUserScriptID());
  3126. + userscript->set_host_id(HostID(HostID::HostType::EXTENSIONS,
  3127. + "_" + base::NumberToString(userscript->id())));
  3128. +
  3129. + std::u16string error;
  3130. + bool found_metadata;
  3131. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &found_metadata, &error)) {
  3132. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3133. + LOG(INFO) << "UserScriptLoader: Found user script " << userscript->name() <<
  3134. + "-" << userscript->version() <<
  3135. + "-" << userscript->description();
  3136. +
  3137. + userscript->set_file_path(full_name.AsUTF8Unsafe());
  3138. + user_scripts_list->push_back(std::move(userscript));
  3139. + } else {
  3140. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3141. + }
  3142. + }
  3143. +}
  3144. +
  3145. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  3146. + UserScriptsPrefs* prefs)
  3147. + : loaded_scripts_(new UserScriptList()),
  3148. + ready_(false),
  3149. + browser_context_(browser_context),
  3150. + prefs_(prefs) {}
  3151. +
  3152. +UserScriptLoader::~UserScriptLoader() {
  3153. + for (auto& observer : observers_)
  3154. + observer.OnUserScriptLoaderDestroyed(this);
  3155. +}
  3156. +
  3157. +void UserScriptLoader::OnRenderProcessHostCreated(
  3158. + content::RenderProcessHost* process_host) {
  3159. + if (initial_load_complete()) {
  3160. + SendUpdate(process_host, shared_memory_);
  3161. + }
  3162. +}
  3163. +
  3164. +void UserScriptLoader::SetReady(bool ready) {
  3165. + bool was_ready = ready_;
  3166. + ready_ = ready;
  3167. + if (ready_ && !was_ready)
  3168. + AttemptLoad();
  3169. +}
  3170. +
  3171. +void UserScriptLoader::AttemptLoad() {
  3172. + int tryOut = prefs_->GetCurrentStartupTryout();
  3173. + if (tryOut >= 3) {
  3174. + LOG(INFO) << "UserScriptLoader: Possible crash detected. UserScript disabled";
  3175. + prefs_->SetEnabled(false);
  3176. + } else {
  3177. + prefs_->StartupTryout(tryOut+1);
  3178. + StartLoad();
  3179. + }
  3180. +}
  3181. +
  3182. +void UserScriptLoader::StartLoad() {
  3183. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3184. +
  3185. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3186. + LOG(INFO) << "UserScriptLoader: StartLoad";
  3187. +
  3188. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  3189. + // the scripts aren't currently ready.
  3190. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  3191. + scripts_to_load->clear();
  3192. +
  3193. + if (prefs_->IsEnabled()) {
  3194. + LoadScripts(std::move(scripts_to_load),
  3195. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  3196. + weak_factory_.GetWeakPtr()));
  3197. + } else {
  3198. + OnScriptsLoaded(std::move(scripts_to_load));
  3199. + }
  3200. +}
  3201. +
  3202. +// static
  3203. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  3204. + const UserScriptList& scripts) {
  3205. + base::Pickle pickle;
  3206. + pickle.WriteUInt32(scripts.size());
  3207. + for (const std::unique_ptr<UserScript>& script : scripts) {
  3208. + // TODO(aa): This can be replaced by sending content script metadata to
  3209. + // renderers along with other extension data in ExtensionMsg_Loaded.
  3210. + // See crbug.com/70516.
  3211. + script->Pickle(&pickle);
  3212. + // Write scripts as 'data' so that we can read it out in the slave without
  3213. + // allocating a new string.
  3214. + for (const std::unique_ptr<UserScript::File>& js_file :
  3215. + script->js_scripts()) {
  3216. + base::StringPiece contents = js_file->GetContent();
  3217. + pickle.WriteData(contents.data(), contents.length());
  3218. + }
  3219. + for (const std::unique_ptr<UserScript::File>& css_file :
  3220. + script->css_scripts()) {
  3221. + base::StringPiece contents = css_file->GetContent();
  3222. + pickle.WriteData(contents.data(), contents.length());
  3223. + }
  3224. + }
  3225. +
  3226. + // Create the shared memory object.
  3227. + base::MappedReadOnlyRegion shared_memory =
  3228. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  3229. + if (!shared_memory.IsValid())
  3230. + return {};
  3231. +
  3232. + // Copy the pickle to shared memory.
  3233. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  3234. + return std::move(shared_memory.region);
  3235. +}
  3236. +
  3237. +void UserScriptLoader::AddObserver(Observer* observer) {
  3238. + observers_.AddObserver(observer);
  3239. +}
  3240. +
  3241. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  3242. + observers_.RemoveObserver(observer);
  3243. +}
  3244. +
  3245. +void UserScriptLoader::OnScriptsLoaded(
  3246. + std::unique_ptr<UserScriptList> user_scripts) {
  3247. +
  3248. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3249. + LOG(INFO) << "UserScriptLoader: OnScriptsLoaded";
  3250. +
  3251. + // Check user preferences for loaded user scripts
  3252. + prefs_->CompareWithPrefs(*user_scripts);
  3253. + loaded_scripts_ = std::move(user_scripts);
  3254. +
  3255. + base::ReadOnlySharedMemoryRegion shared_memory;
  3256. + shared_memory =
  3257. + UserScriptLoader::Serialize(*loaded_scripts_);
  3258. +
  3259. + if (!shared_memory.IsValid()) {
  3260. + // This can happen if we run out of file descriptors. In that case, we
  3261. + // have a choice between silently omitting all user scripts for new tabs,
  3262. + // by nulling out shared_memory_, or only silently omitting new ones by
  3263. + // leaving the existing object in place. The second seems less bad, even
  3264. + // though it removes the possibility that freeing the shared memory block
  3265. + // would open up enough FDs for long enough for a retry to succeed.
  3266. +
  3267. + // Pretend the extension change didn't happen.
  3268. + return;
  3269. + }
  3270. +
  3271. + // We've got scripts ready to go.
  3272. + shared_memory_ = std::move(shared_memory);
  3273. +
  3274. + for (content::RenderProcessHost::iterator i(
  3275. + content::RenderProcessHost::AllHostsIterator());
  3276. + !i.IsAtEnd(); i.Advance()) {
  3277. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  3278. + }
  3279. +
  3280. + // DCHECK(false); trying crash
  3281. + prefs_->StartupTryout(0);
  3282. +
  3283. + for (auto& observer : observers_)
  3284. + observer.OnScriptsLoaded(this, browser_context_);
  3285. +}
  3286. +
  3287. +void UserScriptLoader::SendUpdate(
  3288. + content::RenderProcessHost* process,
  3289. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  3290. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3291. + LOG(INFO) << "UserScriptLoader: SendUpdate";
  3292. +
  3293. + // If the process is being started asynchronously, early return. We'll end up
  3294. + // calling InitUserScripts when it's created which will call this again.
  3295. + base::ProcessHandle handle = process->GetProcess().Handle();
  3296. + if (!handle)
  3297. + return;
  3298. +
  3299. + base::ReadOnlySharedMemoryRegion region_for_process =
  3300. + shared_memory.Duplicate();
  3301. + if (!region_for_process.IsValid())
  3302. + return;
  3303. +
  3304. + process->Send(new ExtensionMsg_UpdateUserScripts(
  3305. + std::move(region_for_process)));
  3306. +}
  3307. +
  3308. +void LoadScriptsOnFileTaskRunner(
  3309. + std::unique_ptr<UserScriptList> user_scripts,
  3310. + UserScriptLoader::LoadScriptsCallback callback) {
  3311. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3312. + DCHECK(user_scripts.get());
  3313. +
  3314. + // load user scripts from path
  3315. + LoadUserScripts(user_scripts.get());
  3316. +
  3317. + // Explicit priority to prevent unwanted task priority inheritance.
  3318. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3319. + ->PostTask(FROM_HERE,
  3320. + base::BindOnce(std::move(callback), std::move(user_scripts)));
  3321. +}
  3322. +
  3323. +void UserScriptLoader::LoadScripts(
  3324. + std::unique_ptr<UserScriptList> user_scripts,
  3325. + LoadScriptsCallback callback) {
  3326. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  3327. +
  3328. + GetUserScriptsFileTaskRunner()->PostTask(
  3329. + FROM_HERE,
  3330. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  3331. + std::move(callback)));
  3332. +}
  3333. +
  3334. +void RemoveScriptsOnFileTaskRunner(
  3335. + const std::string& script_id,
  3336. + UserScriptLoader::RemoveScriptCallback callback) {
  3337. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3338. +
  3339. + base::FilePath path;
  3340. + if (GetOrCreatePath(path)) {
  3341. + base::FilePath file = path.Append(script_id);
  3342. + if (base::DeleteFile(file) == false) {
  3343. + LOG(ERROR) <<
  3344. + "ERROR: failed to delete file : " << path;
  3345. + }
  3346. + }
  3347. +
  3348. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3349. + ->PostTask(FROM_HERE,
  3350. + base::BindOnce(std::move(callback)));
  3351. +}
  3352. +
  3353. +void UserScriptLoader::OnScriptRemoved() {
  3354. + StartLoad();
  3355. +}
  3356. +
  3357. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  3358. + if (!prefs_->IsEnabled()) return;
  3359. + prefs_->RemoveScriptFromPrefs(script_id);
  3360. +
  3361. + GetUserScriptsFileTaskRunner()->PostTask(
  3362. + FROM_HERE,
  3363. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  3364. + std::move(script_id),
  3365. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  3366. + weak_factory_.GetWeakPtr())));
  3367. +}
  3368. +
  3369. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3370. + if (!prefs_->IsEnabled()) return;
  3371. + prefs_->SetScriptEnabled(script_id, is_enabled);
  3372. + StartLoad();
  3373. +}
  3374. +
  3375. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  3376. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3377. +
  3378. + if (!prefs_->IsEnabled()) return;
  3379. +
  3380. + dialog_ = ui::SelectFileDialog::Create(
  3381. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  3382. +
  3383. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  3384. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  3385. + allowed_file_info.allowed_paths =
  3386. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  3387. + base::FilePath suggested_name;
  3388. +
  3389. + std::vector<std::u16string> types;
  3390. + types.push_back(u"*/*"); /*= java SelectFileDialog.ALL_TYPES*/
  3391. + std::pair<std::vector<std::u16string>, bool> accept_types = std::make_pair(
  3392. + types, false /*use_media_capture*/);
  3393. +
  3394. + dialog_->SelectFile(
  3395. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  3396. + std::u16string() /* dialog title*/, suggested_name, &allowed_file_info,
  3397. + 0 /* file type index */, std::string() /* default file extension */,
  3398. + nativeWindow,
  3399. + &accept_types /* params */);
  3400. +}
  3401. +
  3402. +
  3403. +void LoadScriptFromPathOnFileTaskRunner(
  3404. + const base::FilePath& path,
  3405. + const std::string& display_name,
  3406. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  3407. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3408. +
  3409. + std::unique_ptr<UserScript> userscript(new UserScript());
  3410. + std::u16string error;
  3411. + bool found_metadata = false;
  3412. + bool loaded = LoadUserScriptFromFile(path, GURL(), userscript, &found_metadata, &error);
  3413. +
  3414. + bool result = loaded;
  3415. + if (result || found_metadata) {
  3416. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3417. + LOG(INFO) << "UserScriptLoader: found " << userscript->name() <<
  3418. + "-" << userscript->version() <<
  3419. + "-" << userscript->description();
  3420. + base::FilePath destination;
  3421. + if (GetOrCreatePath(destination) == false) {
  3422. + error = u"Cannot create destination.";
  3423. + } else {
  3424. + // we need an unique file name
  3425. + if (display_name.empty() == false) {
  3426. + userscript->set_key(display_name);
  3427. + }
  3428. +
  3429. + // filename is original filename or display_name
  3430. + std::string file_name(userscript->key());
  3431. + base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
  3432. + destination = destination.Append(file_name);
  3433. +
  3434. + if (destination.ReferencesParent()) {
  3435. + error = u"Invalid file name.";
  3436. + result = false;
  3437. + } else if (base::PathExists(destination)) {
  3438. + error = u"User script already loaded.";
  3439. + result = false;
  3440. + } else {
  3441. + if (loaded) {
  3442. + // if is a correct userscript, copy it
  3443. + result = base::CopyFile(path, destination);
  3444. + if (result == false) {
  3445. + error = u"Copy error.";
  3446. + }
  3447. + } else {
  3448. + // else, there is a parser error
  3449. + // write minimal values and the error string, so UI can show it
  3450. + std::string combined_string = base::StrCat({
  3451. + kUserScriptBegin, "\n",
  3452. + kNamespaceDeclaration, " ", userscript->name_space(), "\n",
  3453. + kNameDeclaration, " ", userscript->name(), "\n",
  3454. + kVersionDeclaration, " ", userscript->version(), "\n",
  3455. + kDescriptionDeclaration, " ", userscript->description(), "\n",
  3456. + kUrlSourceDeclaration, " ", userscript->url_source(), "\n",
  3457. + kParserError, " ", base::UTF16ToASCII(error), "\n",
  3458. + kForceDisabled, " true\n",
  3459. + kUserScriptEnd, "\n"
  3460. + });
  3461. +
  3462. + if (!base::WriteFile(destination, combined_string)) {
  3463. + error = u"Cannot write.";
  3464. + result = false;
  3465. + }
  3466. + }
  3467. + }
  3468. + }
  3469. + }
  3470. +
  3471. + if (!error.empty()) {
  3472. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3473. + }
  3474. +
  3475. + // return to callback with eventually the error
  3476. + const std::string string_error = base::UTF16ToASCII(error);
  3477. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3478. + ->PostTask(FROM_HERE,
  3479. + base::BindOnce(std::move(callback), result,
  3480. + std::move(string_error)));
  3481. +}
  3482. +
  3483. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  3484. + if (!prefs_->IsEnabled()) return;
  3485. +
  3486. + std::u16string file_display_name;
  3487. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  3488. +
  3489. + std::string display_name = script_path.BaseName().value();
  3490. + if (base::IsStringASCII(file_display_name))
  3491. + display_name = base::UTF16ToASCII(file_display_name);
  3492. +
  3493. + GetUserScriptsFileTaskRunner()->PostTask(
  3494. + FROM_HERE,
  3495. + base::BindOnce(
  3496. + &LoadScriptFromPathOnFileTaskRunner,
  3497. + script_path, display_name,
  3498. + base::BindOnce(
  3499. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  3500. + weak_factory_.GetWeakPtr()
  3501. + )
  3502. + ));
  3503. +}
  3504. +
  3505. +void UserScriptLoader::FileSelected(
  3506. + const base::FilePath& path, int index, void* params) {
  3507. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3508. + LOG(INFO) << "UserScriptLoader: FileSelected " << path;
  3509. +
  3510. + UserScriptLoader::TryToInstall(path);
  3511. +}
  3512. +
  3513. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  3514. + bool result, const std::string& error) {
  3515. + for (auto& observer : observers_)
  3516. + observer.OnUserScriptLoaded(this, result, error);
  3517. +
  3518. + StartLoad();
  3519. +}
  3520. +
  3521. +void UserScriptLoader::FileSelectionCanceled(
  3522. + void* params) {
  3523. +}
  3524. +
  3525. +} // namespace extensions
  3526. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  3527. new file mode 100755
  3528. --- /dev/null
  3529. +++ b/components/user_scripts/browser/user_script_loader.h
  3530. @@ -0,0 +1,169 @@
  3531. +/*
  3532. + This file is part of Bromite.
  3533. +
  3534. + Bromite is free software: you can redistribute it and/or modify
  3535. + it under the terms of the GNU General Public License as published by
  3536. + the Free Software Foundation, either version 3 of the License, or
  3537. + (at your option) any later version.
  3538. +
  3539. + Bromite is distributed in the hope that it will be useful,
  3540. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3541. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3542. + GNU General Public License for more details.
  3543. +
  3544. + You should have received a copy of the GNU General Public License
  3545. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3546. +*/
  3547. +
  3548. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3549. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3550. +
  3551. +#include <map>
  3552. +#include <memory>
  3553. +#include <set>
  3554. +
  3555. +#include "base/callback_forward.h"
  3556. +#include "base/compiler_specific.h"
  3557. +#include "base/memory/read_only_shared_memory_region.h"
  3558. +#include "base/memory/weak_ptr.h"
  3559. +#include "base/observer_list.h"
  3560. +#include "content/public/browser/render_process_host_creation_observer.h"
  3561. +#include "ui/shell_dialogs/select_file_dialog.h"
  3562. +#include "content/browser/file_system_access/file_system_chooser.h"
  3563. +#include "ui/android/window_android.h"
  3564. +
  3565. +#include "../common/host_id.h"
  3566. +#include "../common/user_script.h"
  3567. +#include "user_script_prefs.h"
  3568. +
  3569. +namespace base {
  3570. +class ReadOnlySharedMemoryRegion;
  3571. +}
  3572. +
  3573. +namespace content {
  3574. +class BrowserContext;
  3575. +class RenderProcessHost;
  3576. +}
  3577. +
  3578. +namespace user_scripts {
  3579. +
  3580. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  3581. +// new shared memory region when the set of scripts changes. Also notifies
  3582. +// renderers of new shared memory region when new renderers appear, or when
  3583. +// script reloading completes. Script loading lives on the file thread.
  3584. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  3585. + public ui::SelectFileDialog::Listener {
  3586. + public:
  3587. + UserScriptLoader(const UserScriptLoader&) = delete;
  3588. + UserScriptLoader& operator=(const UserScriptLoader&) = delete;
  3589. + using LoadScriptsCallback =
  3590. + base::OnceCallback<void(std::unique_ptr<UserScriptList>)>;
  3591. + using LoadSingleScriptCallback =
  3592. + base::OnceCallback<void(bool result, const std::string& error)>;
  3593. +
  3594. + using RemoveScriptCallback =
  3595. + base::OnceCallback<void()>;
  3596. + class Observer {
  3597. + public:
  3598. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  3599. + content::BrowserContext* browser_context) = 0;
  3600. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  3601. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  3602. + bool result, const std::string& error) = 0;
  3603. + };
  3604. +
  3605. + // Parses the includes out of |script| and returns them in |includes|.
  3606. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  3607. + std::unique_ptr<UserScript>& script,
  3608. + bool *found_metadata,
  3609. + std::string& error_message);
  3610. +
  3611. + UserScriptLoader(content::BrowserContext* browser_context,
  3612. + UserScriptsPrefs* prefs);
  3613. + //const HostID& host_id);
  3614. + ~UserScriptLoader() override;
  3615. +
  3616. + // Initiates procedure to start loading scripts on the file thread.
  3617. + void StartLoad();
  3618. +
  3619. + // Returns true if we have any scripts ready.
  3620. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  3621. +
  3622. + // Pickle user scripts and return pointer to the shared memory.
  3623. + static base::ReadOnlySharedMemoryRegion Serialize(
  3624. + const user_scripts::UserScriptList& scripts);
  3625. +
  3626. + // Adds or removes observers.
  3627. + void AddObserver(Observer* observer);
  3628. + void RemoveObserver(Observer* observer);
  3629. +
  3630. + // Sets the flag if the initial set of hosts has finished loading; if it's
  3631. + // set to be true, calls AttempLoad() to bootstrap.
  3632. + void SetReady(bool ready);
  3633. +
  3634. + void RemoveScript(const std::string& script_id);
  3635. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3636. +
  3637. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  3638. + void TryToInstall(const base::FilePath& script_path);
  3639. +
  3640. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  3641. + LoadScriptsCallback callback);
  3642. +
  3643. + protected:
  3644. + content::BrowserContext* browser_context() const { return browser_context_; }
  3645. +
  3646. + UserScriptsPrefs* prefs() const { return prefs_; }
  3647. +
  3648. + private:
  3649. + void OnRenderProcessHostCreated(
  3650. + content::RenderProcessHost* process_host) override;
  3651. +
  3652. + // Attempts to initiate a load.
  3653. + void AttemptLoad();
  3654. +
  3655. + // Called once we have finished loading the scripts on the file thread.
  3656. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts);
  3657. +
  3658. + // Sends the renderer process a new set of user scripts. If
  3659. + // |changed_hosts| is not empty, this signals that only the scripts from
  3660. + // those hosts should be updated. Otherwise, all hosts will be
  3661. + // updated.
  3662. + void SendUpdate(content::RenderProcessHost* process,
  3663. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  3664. +
  3665. + // Contains the scripts that were found the last time scripts were updated.
  3666. + base::ReadOnlySharedMemoryRegion shared_memory_;
  3667. +
  3668. + // List of scripts that are currently loaded. This is null when a load is in
  3669. + // progress.
  3670. + std::unique_ptr<UserScriptList> loaded_scripts_;
  3671. +
  3672. + // If the initial set of hosts has finished loading.
  3673. + bool ready_;
  3674. +
  3675. + // The browser_context for which the scripts managed here are installed.
  3676. + content::BrowserContext* browser_context_;
  3677. +
  3678. + // Manage load and store from preferences
  3679. + UserScriptsPrefs* prefs_;
  3680. +
  3681. + // The associated observers.
  3682. + base::ObserverList<Observer>::Unchecked observers_;
  3683. +
  3684. + void OnScriptRemoved();
  3685. +
  3686. + // Manage file dialog requests
  3687. + scoped_refptr<ui::SelectFileDialog> dialog_;
  3688. + void FileSelected(const base::FilePath& path,
  3689. + int index, void* params) override;
  3690. + void FileSelectionCanceled(void* params) override;
  3691. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  3692. + bool result, const std::string& error );
  3693. +
  3694. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  3695. +};
  3696. +
  3697. +} // namespace extensions
  3698. +
  3699. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3700. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  3701. new file mode 100644
  3702. --- /dev/null
  3703. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  3704. @@ -0,0 +1,34 @@
  3705. +/*
  3706. + This file is part of Bromite.
  3707. +
  3708. + Bromite is free software: you can redistribute it and/or modify
  3709. + it under the terms of the GNU General Public License as published by
  3710. + the Free Software Foundation, either version 3 of the License, or
  3711. + (at your option) any later version.
  3712. +
  3713. + Bromite is distributed in the hope that it will be useful,
  3714. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3715. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3716. + GNU General Public License for more details.
  3717. +
  3718. + You should have received a copy of the GNU General Public License
  3719. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3720. +*/
  3721. +
  3722. +#include "user_script_pref_info.h"
  3723. +
  3724. +namespace user_scripts {
  3725. +
  3726. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  3727. + const std::string& description,
  3728. + const base::Time& install_time,
  3729. + bool enabled)
  3730. + : install_time(install_time),
  3731. + enabled(enabled),
  3732. + name_(name),
  3733. + description_(description) {}
  3734. +
  3735. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  3736. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  3737. +
  3738. +}
  3739. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3740. new file mode 100644
  3741. --- /dev/null
  3742. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3743. @@ -0,0 +1,72 @@
  3744. +/*
  3745. + This file is part of Bromite.
  3746. +
  3747. + Bromite is free software: you can redistribute it and/or modify
  3748. + it under the terms of the GNU General Public License as published by
  3749. + the Free Software Foundation, either version 3 of the License, or
  3750. + (at your option) any later version.
  3751. +
  3752. + Bromite is distributed in the hope that it will be useful,
  3753. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3754. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3755. + GNU General Public License for more details.
  3756. +
  3757. + You should have received a copy of the GNU General Public License
  3758. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3759. +*/
  3760. +
  3761. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3762. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3763. +
  3764. +#include "base/values.h"
  3765. +#include "base/time/time.h"
  3766. +#include "components/keyed_service/core/keyed_service.h"
  3767. +
  3768. +namespace user_scripts {
  3769. +
  3770. +class UserScriptsListPrefs : public KeyedService {
  3771. + public:
  3772. + struct ScriptInfo {
  3773. + ScriptInfo(const std::string& name,
  3774. + const std::string& description,
  3775. + const base::Time& install_time,
  3776. + bool enabled);
  3777. + ScriptInfo(const ScriptInfo& other);
  3778. + ~ScriptInfo();
  3779. +
  3780. + const std::string& name() const { return name_; }
  3781. + void set_name(const std::string& name) { name_ = name; }
  3782. +
  3783. + const std::string& description() const { return description_; }
  3784. + void set_description(const std::string& description) { description_ = description; }
  3785. +
  3786. + const std::string& version() const { return version_; }
  3787. + void set_version(const std::string& version) { version_ = version; }
  3788. +
  3789. + const std::string& file_path() const { return file_path_; }
  3790. + void set_file_path(const std::string& file_path) { file_path_ = file_path; }
  3791. +
  3792. + const std::string& url_source() const { return url_source_; }
  3793. + void set_url_source(const std::string& url_source) { url_source_ = url_source; }
  3794. +
  3795. + const std::string& parser_error() const { return parser_error_; }
  3796. + void set_parser_error(const std::string& parser_error) { parser_error_ = parser_error; }
  3797. +
  3798. + base::Time install_time;
  3799. + bool enabled;
  3800. +
  3801. + bool force_disabled;
  3802. +
  3803. + private:
  3804. + std::string name_;
  3805. + std::string description_;
  3806. + std::string version_;
  3807. + std::string file_path_;
  3808. + std::string url_source_;
  3809. + std::string parser_error_;
  3810. + };
  3811. +};
  3812. +
  3813. +}
  3814. +
  3815. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3816. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3817. new file mode 100644
  3818. --- /dev/null
  3819. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3820. @@ -0,0 +1,278 @@
  3821. +/*
  3822. + This file is part of Bromite.
  3823. +
  3824. + Bromite is free software: you can redistribute it and/or modify
  3825. + it under the terms of the GNU General Public License as published by
  3826. + the Free Software Foundation, either version 3 of the License, or
  3827. + (at your option) any later version.
  3828. +
  3829. + Bromite is distributed in the hope that it will be useful,
  3830. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3831. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3832. + GNU General Public License for more details.
  3833. +
  3834. + You should have received a copy of the GNU General Public License
  3835. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3836. +*/
  3837. +
  3838. +#include <map>
  3839. +
  3840. +#include "base/values.h"
  3841. +#include "base/strings/string_number_conversions.h"
  3842. +#include "base/json/json_writer.h"
  3843. +
  3844. +#include "chrome/browser/browser_process.h"
  3845. +#include "chrome/browser/profiles/profile.h"
  3846. +#include "chrome/browser/profiles/profile_manager.h"
  3847. +
  3848. +#include "components/prefs/pref_registry_simple.h"
  3849. +#include "components/prefs/pref_service.h"
  3850. +#include "components/prefs/scoped_user_pref_update.h"
  3851. +#include "components/pref_registry/pref_registry_syncable.h"
  3852. +#include "user_script_prefs.h"
  3853. +#include "user_script_pref_info.h"
  3854. +#include "../common/user_script.h"
  3855. +#include "../common/user_scripts_features.h"
  3856. +
  3857. +namespace user_scripts {
  3858. +
  3859. +namespace prefs {
  3860. + const char kUserScriptsEnabled[] = "userscripts.enabled";
  3861. +}
  3862. +
  3863. +namespace {
  3864. +
  3865. +const char kUserScriptsStartup[] = "userscripts.startup";
  3866. +
  3867. +const char kUserScriptsList[] = "userscripts.scripts";
  3868. +const char kScriptIsEnabled[] = "enabled";
  3869. +const char kScriptName[] = "name";
  3870. +const char kScriptDescription[] = "description";
  3871. +const char kScriptVersion[] = "version";
  3872. +const char kScriptInstallTime[] = "install_time";
  3873. +const char kScriptFilePath[] = "file_path";
  3874. +const char kScriptUrlSource[] = "url_source";
  3875. +const char kScriptParserError[] = "parser_error";
  3876. +const char kScriptForceDisabled[] = "force_disabled";
  3877. +
  3878. +class PrefUpdate : public DictionaryPrefUpdate {
  3879. + public:
  3880. + PrefUpdate(PrefService* service,
  3881. + const std::string& id,
  3882. + const std::string& path)
  3883. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3884. +
  3885. + PrefUpdate(const PrefUpdate&) = delete;
  3886. + PrefUpdate& operator=(const PrefUpdate&) = delete;
  3887. + ~PrefUpdate() override = default;
  3888. +
  3889. + base::Value* Get() override {
  3890. + base::Value* dict = DictionaryPrefUpdate::Get();
  3891. + base::Value* dict_item =
  3892. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3893. + if (!dict_item)
  3894. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3895. + return dict_item;
  3896. + }
  3897. +
  3898. + private:
  3899. + const std::string id_;
  3900. +};
  3901. +
  3902. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3903. + const std::string& key,
  3904. + int64_t* value) {
  3905. + DCHECK(dict);
  3906. + const std::string* value_str = dict->FindStringKey(key);
  3907. + if (!value_str) {
  3908. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3909. + << ".";
  3910. + return false;
  3911. + }
  3912. +
  3913. + if (!base::StringToInt64(*value_str, value)) {
  3914. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3915. + << *value_str << ".";
  3916. + return false;
  3917. + }
  3918. +
  3919. + return true;
  3920. +}
  3921. +
  3922. +}
  3923. +
  3924. +UserScriptsPrefs::UserScriptsPrefs(
  3925. + PrefService* prefs)
  3926. + : prefs_(prefs) {
  3927. +}
  3928. +
  3929. +// static
  3930. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3931. + registry->RegisterBooleanPref(prefs::kUserScriptsEnabled, false);
  3932. + registry->RegisterIntegerPref(kUserScriptsStartup, 0);
  3933. + registry->RegisterDictionaryPref(kUserScriptsList);
  3934. +}
  3935. +
  3936. +bool UserScriptsPrefs::IsEnabled() {
  3937. + return prefs_->GetBoolean(prefs::kUserScriptsEnabled);
  3938. +}
  3939. +
  3940. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3941. + prefs_->SetBoolean(prefs::kUserScriptsEnabled, enabled);
  3942. + prefs_->CommitPendingWrite();
  3943. +}
  3944. +
  3945. +void UserScriptsPrefs::StartupTryout(int number) {
  3946. + prefs_->SetInteger(kUserScriptsStartup, number);
  3947. + prefs_->CommitPendingWrite();
  3948. +}
  3949. +
  3950. +int UserScriptsPrefs::GetCurrentStartupTryout() {
  3951. + return prefs_->GetInteger(kUserScriptsStartup);
  3952. +}
  3953. +
  3954. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3955. + if (IsEnabled() == false) {
  3956. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3957. + LOG(INFO) << "UserScriptsPrefs: disabled by user";
  3958. +
  3959. + user_scripts.clear();
  3960. + return;
  3961. + }
  3962. +
  3963. + std::vector<std::string> all_scripts;
  3964. +
  3965. + auto it = user_scripts.begin();
  3966. + while (it != user_scripts.end())
  3967. + {
  3968. + std::string key = it->get()->key();
  3969. + all_scripts.push_back(key);
  3970. +
  3971. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  3972. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  3973. +
  3974. + // add or update prefs
  3975. + scriptInfo->set_name(it->get()->name());
  3976. + scriptInfo->set_description(it->get()->description());
  3977. + scriptInfo->set_version(it->get()->version());
  3978. + scriptInfo->set_file_path(it->get()->file_path());
  3979. + scriptInfo->set_url_source(it->get()->url_source());
  3980. + scriptInfo->set_parser_error(it->get()->parser_error());
  3981. + scriptInfo->force_disabled = (it->get()->force_disabled());
  3982. +
  3983. + PrefUpdate update(prefs_, key, kUserScriptsList);
  3984. + base::Value* script_dict = update.Get();
  3985. +
  3986. + script_dict->SetStringKey(kScriptName, scriptInfo->name());
  3987. + script_dict->SetStringKey(kScriptDescription, scriptInfo->description());
  3988. + script_dict->SetBoolKey(kScriptIsEnabled, scriptInfo->enabled);
  3989. + script_dict->SetStringKey(kScriptVersion, scriptInfo->version());
  3990. + script_dict->SetStringKey(kScriptFilePath, scriptInfo->file_path());
  3991. + script_dict->SetStringKey(kScriptUrlSource, scriptInfo->url_source());
  3992. + script_dict->SetStringKey(kScriptParserError, scriptInfo->parser_error());
  3993. + script_dict->SetBoolKey(kScriptForceDisabled, scriptInfo->force_disabled);
  3994. +
  3995. + std::string install_time_str =
  3996. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  3997. + script_dict->SetStringKey(kScriptInstallTime, install_time_str);
  3998. +
  3999. + if (!scriptInfo->enabled) {
  4000. + it = user_scripts.erase(it);
  4001. + } else {
  4002. + ++it;
  4003. + }
  4004. + }
  4005. +
  4006. + // remove script from prefs if no more present
  4007. + std::vector<std::string> all_scripts_to_remove;
  4008. + const base::DictionaryValue* dict =
  4009. + &base::Value::AsDictionaryValue(*prefs_->GetDictionary(
  4010. + kUserScriptsList));
  4011. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  4012. + script_it.Advance()) {
  4013. + const std::string& key = script_it.key();
  4014. +
  4015. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  4016. + all_scripts_to_remove.push_back(key);
  4017. + }
  4018. + }
  4019. +
  4020. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4021. + base::Value* const update_dict = update.Get();
  4022. + for (auto key : all_scripts_to_remove) {
  4023. + update_dict->RemoveKey(key);
  4024. + }
  4025. +
  4026. + return;
  4027. +}
  4028. +
  4029. +std::string UserScriptsPrefs::GetScriptsInfo() {
  4030. + std::string json_string;
  4031. +
  4032. + const base::Value* dict =
  4033. + prefs_->GetDictionary(kUserScriptsList);
  4034. +
  4035. + if (dict) {
  4036. + base::JSONWriter::WriteWithOptions(
  4037. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  4038. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  4039. + }
  4040. +
  4041. + return json_string;
  4042. +}
  4043. +
  4044. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  4045. + const std::string& script_id) const {
  4046. +
  4047. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  4048. + script_id, "", base::Time::Now(), false);
  4049. +
  4050. + const base::Value* scripts =
  4051. + prefs_->GetDictionary(kUserScriptsList);
  4052. + if (!scripts)
  4053. + return scriptInfo;
  4054. +
  4055. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  4056. + scripts->FindDictKey(script_id));
  4057. + if (!script)
  4058. + return scriptInfo;
  4059. +
  4060. + const std::string* name = script->FindStringKey(kScriptName);
  4061. + const std::string* description = script->FindStringKey(kScriptDescription);
  4062. + const std::string* version = script->FindStringKey(kScriptVersion);
  4063. + const std::string* file_path = script->FindStringKey(kScriptFilePath);
  4064. + const std::string* url_source = script->FindStringKey(kScriptUrlSource);
  4065. + const std::string* parser_error = script->FindStringKey(kScriptParserError);
  4066. +
  4067. + scriptInfo->set_name( name ? *name : "no name" );
  4068. + scriptInfo->set_description( description ? *description : "no description" );
  4069. + scriptInfo->set_version( version ? *version : "no version" );
  4070. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  4071. + scriptInfo->set_file_path( file_path ? *file_path : "no file path" );
  4072. + scriptInfo->set_url_source( url_source ? *url_source : "" );
  4073. + scriptInfo->set_parser_error( parser_error ? *parser_error : "" );
  4074. + scriptInfo->force_disabled = script->FindBoolKey(kScriptForceDisabled).value_or(false);
  4075. +
  4076. + int64_t time_interval = 0;
  4077. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  4078. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  4079. + }
  4080. +
  4081. + return scriptInfo;
  4082. +}
  4083. +
  4084. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  4085. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4086. + base::Value* const update_dict = update.Get();
  4087. + update_dict->RemoveKey(script_id);
  4088. +}
  4089. +
  4090. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  4091. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  4092. + base::Value* script_dict = update.Get();
  4093. + if (script_dict->FindBoolKey(kScriptForceDisabled).value_or(false))
  4094. + is_enabled = true;
  4095. + script_dict->SetBoolKey(kScriptIsEnabled, is_enabled);
  4096. +}
  4097. +
  4098. +}
  4099. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  4100. new file mode 100644
  4101. --- /dev/null
  4102. +++ b/components/user_scripts/browser/user_script_prefs.h
  4103. @@ -0,0 +1,62 @@
  4104. +/*
  4105. + This file is part of Bromite.
  4106. +
  4107. + Bromite is free software: you can redistribute it and/or modify
  4108. + it under the terms of the GNU General Public License as published by
  4109. + the Free Software Foundation, either version 3 of the License, or
  4110. + (at your option) any later version.
  4111. +
  4112. + Bromite is distributed in the hope that it will be useful,
  4113. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4114. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4115. + GNU General Public License for more details.
  4116. +
  4117. + You should have received a copy of the GNU General Public License
  4118. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4119. +*/
  4120. +
  4121. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4122. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4123. +
  4124. +#include "content/public/browser/browser_context.h"
  4125. +#include "components/prefs/pref_service.h"
  4126. +#include "components/pref_registry/pref_registry_syncable.h"
  4127. +
  4128. +#include "user_script_pref_info.h"
  4129. +#include "../common/user_script.h"
  4130. +
  4131. +namespace user_scripts {
  4132. +
  4133. +namespace prefs {
  4134. + extern const char kUserScriptsEnabled[];
  4135. +}
  4136. +
  4137. +class UserScriptsPrefs {
  4138. + public:
  4139. + UserScriptsPrefs(
  4140. + PrefService* prefs);
  4141. +
  4142. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  4143. +
  4144. + bool IsEnabled();
  4145. + void SetEnabled(bool enabled);
  4146. +
  4147. + void StartupTryout(int number);
  4148. + int GetCurrentStartupTryout();
  4149. +
  4150. + void CompareWithPrefs(UserScriptList& user_scripts);
  4151. +
  4152. + std::string GetScriptsInfo();
  4153. + void RemoveScriptFromPrefs(const std::string& script_id);
  4154. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  4155. +
  4156. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  4157. + const std::string& script_id) const;
  4158. +
  4159. + private:
  4160. + PrefService* prefs_;
  4161. +};
  4162. +
  4163. +}
  4164. +
  4165. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4166. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  4167. new file mode 100755
  4168. --- /dev/null
  4169. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  4170. @@ -0,0 +1,78 @@
  4171. +/*
  4172. + This file is part of Bromite.
  4173. +
  4174. + Bromite is free software: you can redistribute it and/or modify
  4175. + it under the terms of the GNU General Public License as published by
  4176. + the Free Software Foundation, either version 3 of the License, or
  4177. + (at your option) any later version.
  4178. +
  4179. + Bromite is distributed in the hope that it will be useful,
  4180. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4181. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4182. + GNU General Public License for more details.
  4183. +
  4184. + You should have received a copy of the GNU General Public License
  4185. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4186. +*/
  4187. +
  4188. +#include "userscripts_browser_client.h"
  4189. +
  4190. +#include "base/logging.h"
  4191. +
  4192. +#include "chrome/browser/browser_process.h"
  4193. +
  4194. +#include "chrome/browser/profiles/profile.h"
  4195. +#include "chrome/browser/profiles/profile_manager.h"
  4196. +
  4197. +#include "../common/user_scripts_features.h"
  4198. +#include "user_script_loader.h"
  4199. +#include "file_task_runner.h"
  4200. +#include "user_script_prefs.h"
  4201. +
  4202. +namespace user_scripts {
  4203. +
  4204. +namespace {
  4205. +
  4206. +// remember: was ExtensionsBrowserClient
  4207. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  4208. +
  4209. +} // namespace
  4210. +
  4211. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  4212. +
  4213. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  4214. +
  4215. +// static
  4216. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  4217. + // only for browser process
  4218. + if (!g_browser_process)
  4219. + return NULL;
  4220. +
  4221. + // singleton
  4222. + if (g_userscripts_browser_client)
  4223. + return g_userscripts_browser_client;
  4224. +
  4225. + // make file task runner
  4226. + GetUserScriptsFileTaskRunner().get();
  4227. +
  4228. + // new instance singleton
  4229. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  4230. +
  4231. + return g_userscripts_browser_client;
  4232. +}
  4233. +
  4234. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  4235. + browser_context_ = context;
  4236. +
  4237. + prefs_ =
  4238. + std::make_unique<user_scripts::UserScriptsPrefs>(
  4239. + static_cast<Profile*>(context)->GetPrefs());
  4240. +
  4241. + userscript_loader_ =
  4242. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  4243. + if (prefs_->IsEnabled()) {
  4244. + userscript_loader_->SetReady(true);
  4245. + }
  4246. +}
  4247. +
  4248. +} // namespace user_scripts
  4249. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  4250. new file mode 100755
  4251. --- /dev/null
  4252. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  4253. @@ -0,0 +1,62 @@
  4254. +/*
  4255. + This file is part of Bromite.
  4256. +
  4257. + Bromite is free software: you can redistribute it and/or modify
  4258. + it under the terms of the GNU General Public License as published by
  4259. + the Free Software Foundation, either version 3 of the License, or
  4260. + (at your option) any later version.
  4261. +
  4262. + Bromite is distributed in the hope that it will be useful,
  4263. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4264. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4265. + GNU General Public License for more details.
  4266. +
  4267. + You should have received a copy of the GNU General Public License
  4268. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4269. +*/
  4270. +
  4271. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4272. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4273. +
  4274. +#include <memory>
  4275. +#include <string>
  4276. +#include <vector>
  4277. +
  4278. +#include "content/public/browser/browser_context.h"
  4279. +
  4280. +#include "../common/user_script.h"
  4281. +#include "user_script_loader.h"
  4282. +#include "user_script_prefs.h"
  4283. +
  4284. +namespace user_scripts {
  4285. +
  4286. +class UserScriptsBrowserClient {
  4287. + public:
  4288. + UserScriptsBrowserClient();
  4289. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  4290. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  4291. + virtual ~UserScriptsBrowserClient();
  4292. +
  4293. + // Returns the single instance of |this|.
  4294. + static UserScriptsBrowserClient* GetInstance();
  4295. +
  4296. + void SetProfile(content::BrowserContext* context);
  4297. +
  4298. + user_scripts::UserScriptsPrefs* GetPrefs() {
  4299. + return prefs_.get();
  4300. + }
  4301. +
  4302. + user_scripts::UserScriptLoader* GetLoader() {
  4303. + return userscript_loader_.get();
  4304. + }
  4305. +
  4306. + private:
  4307. + std::unique_ptr<UserScriptList> scripts_;
  4308. + content::BrowserContext* browser_context_;
  4309. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  4310. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  4311. +};
  4312. +
  4313. +} // namespace extensions
  4314. +
  4315. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4316. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  4317. new file mode 100755
  4318. --- /dev/null
  4319. +++ b/components/user_scripts/common/BUILD.gn
  4320. @@ -0,0 +1,49 @@
  4321. +# Copyright 2014 The Chromium Authors. All rights reserved.
  4322. +# Use of this source code is governed by a BSD-style license that can be
  4323. +# found in the LICENSE file.
  4324. +
  4325. +import("//build/config/features.gni")
  4326. +import("//mojo/public/tools/bindings/mojom.gni")
  4327. +
  4328. +static_library("common") {
  4329. + sources = [
  4330. + "user_scripts_features.cc",
  4331. + "user_scripts_features.h",
  4332. + "constants.h",
  4333. + "host_id.cc",
  4334. + "host_id.h",
  4335. + "script_constants.h",
  4336. + "url_pattern_set.cc",
  4337. + "url_pattern_set.h",
  4338. + "url_pattern.cc",
  4339. + "url_pattern.h",
  4340. + "user_script.cc",
  4341. + "user_script.h",
  4342. + "view_type.cc",
  4343. + "view_type.h",
  4344. + "extension_messages.cc",
  4345. + "extension_messages.h",
  4346. + "extension_message_generator.cc",
  4347. + "extension_message_generator.h",
  4348. + ]
  4349. +
  4350. + configs += [
  4351. + "//build/config:precompiled_headers",
  4352. + "//build/config/compiler:wexit_time_destructors",
  4353. + ]
  4354. +
  4355. + public_deps = [
  4356. + "//components/services/app_service/public/cpp:app_file_handling",
  4357. + "//content/public/common",
  4358. + "//ipc",
  4359. + "//skia",
  4360. + ]
  4361. +
  4362. + deps = [
  4363. + "//base",
  4364. + "//components/url_formatter",
  4365. + "//components/url_matcher",
  4366. + "//components/version_info",
  4367. + "//crypto",
  4368. + ]
  4369. +}
  4370. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  4371. new file mode 100755
  4372. --- /dev/null
  4373. +++ b/components/user_scripts/common/constants.h
  4374. @@ -0,0 +1,21 @@
  4375. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4376. +// Use of this source code is governed by a BSD-style license that can be
  4377. +// found in the LICENSE file.
  4378. +
  4379. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  4380. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  4381. +
  4382. +#include "base/files/file_path.h"
  4383. +#include "base/strings/string_piece_forward.h"
  4384. +#include "components/services/app_service/public/mojom/types.mojom.h"
  4385. +#include "components/version_info/channel.h"
  4386. +#include "ui/base/layout.h"
  4387. +
  4388. +namespace user_scripts {
  4389. +
  4390. +// The origin of injected CSS.
  4391. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  4392. +
  4393. +} // namespace user_scripts
  4394. +
  4395. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  4396. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  4397. new file mode 100755
  4398. --- /dev/null
  4399. +++ b/components/user_scripts/common/error_utils.cc
  4400. @@ -0,0 +1,54 @@
  4401. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4402. +// Use of this source code is governed by a BSD-style license that can be
  4403. +// found in the LICENSE file.
  4404. +
  4405. +#include "error_utils.h"
  4406. +
  4407. +#include <initializer_list>
  4408. +
  4409. +#include "base/check_op.h"
  4410. +#include "base/strings/string_tokenizer.h"
  4411. +#include "base/strings/string_util.h"
  4412. +#include "base/strings/utf_string_conversions.h"
  4413. +
  4414. +namespace user_scripts {
  4415. +
  4416. +namespace {
  4417. +
  4418. +std::string FormatErrorMessageInternal(
  4419. + base::StringPiece format,
  4420. + std::initializer_list<base::StringPiece> args) {
  4421. + std::string format_str = format.as_string();
  4422. + base::StringTokenizer tokenizer(format_str, "*");
  4423. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  4424. +
  4425. + std::vector<base::StringPiece> result_pieces;
  4426. + auto* args_it = args.begin();
  4427. + while (tokenizer.GetNext()) {
  4428. + if (!tokenizer.token_is_delim()) {
  4429. + result_pieces.push_back(tokenizer.token_piece());
  4430. + continue;
  4431. + }
  4432. +
  4433. + CHECK_NE(args_it, args.end())
  4434. + << "More placeholders (*) than substitutions.";
  4435. +
  4436. + // Substitute the argument.
  4437. + result_pieces.push_back(*args_it);
  4438. + args_it++;
  4439. + }
  4440. +
  4441. + // Not all substitutions were consumed.
  4442. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  4443. +
  4444. + return base::JoinString(result_pieces, "" /* separator */);
  4445. +}
  4446. +
  4447. +} // namespace
  4448. +
  4449. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  4450. + base::StringPiece s1) {
  4451. + return FormatErrorMessageInternal(format, {s1});
  4452. +}
  4453. +
  4454. +} // namespace user_scripts
  4455. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  4456. new file mode 100755
  4457. --- /dev/null
  4458. +++ b/components/user_scripts/common/error_utils.h
  4459. @@ -0,0 +1,24 @@
  4460. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4461. +// Use of this source code is governed by a BSD-style license that can be
  4462. +// found in the LICENSE file.
  4463. +
  4464. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4465. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4466. +
  4467. +#include <string>
  4468. +
  4469. +#include "base/strings/string_piece.h"
  4470. +
  4471. +namespace user_scripts {
  4472. +
  4473. +class ErrorUtils {
  4474. + public:
  4475. + // Creates an error messages from a pattern.
  4476. + static std::string FormatErrorMessage(base::StringPiece format,
  4477. + base::StringPiece s1);
  4478. +
  4479. +};
  4480. +
  4481. +} // namespace extensions
  4482. +
  4483. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4484. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  4485. new file mode 100755
  4486. --- /dev/null
  4487. +++ b/components/user_scripts/common/extension_message_generator.cc
  4488. @@ -0,0 +1,29 @@
  4489. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4490. +// Use of this source code is governed by a BSD-style license that can be
  4491. +// found in the LICENSE file.
  4492. +
  4493. +// Get basic type definitions.
  4494. +#define IPC_MESSAGE_IMPL
  4495. +#include "components/user_scripts/common/extension_message_generator.h"
  4496. +
  4497. +// Generate constructors.
  4498. +#include "ipc/struct_constructor_macros.h"
  4499. +#include "components/user_scripts/common/extension_message_generator.h"
  4500. +
  4501. +// Generate param traits write methods.
  4502. +#include "ipc/param_traits_write_macros.h"
  4503. +namespace IPC {
  4504. +#include "components/user_scripts/common/extension_message_generator.h"
  4505. +} // namespace IPC
  4506. +
  4507. +// Generate param traits read methods.
  4508. +#include "ipc/param_traits_read_macros.h"
  4509. +namespace IPC {
  4510. +#include "components/user_scripts/common/extension_message_generator.h"
  4511. +} // namespace IPC
  4512. +
  4513. +// Generate param traits log methods.
  4514. +#include "ipc/param_traits_log_macros.h"
  4515. +namespace IPC {
  4516. +#include "components/user_scripts/common/extension_message_generator.h"
  4517. +} // namespace IPC
  4518. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  4519. new file mode 100755
  4520. --- /dev/null
  4521. +++ b/components/user_scripts/common/extension_message_generator.h
  4522. @@ -0,0 +1,11 @@
  4523. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4524. +// Use of this source code is governed by a BSD-style license that can be
  4525. +// found in the LICENSE file.
  4526. +
  4527. +// Multiply-included file, hence no include guard.
  4528. +
  4529. +#undef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4530. +#include "extension_messages.h"
  4531. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4532. +#error "Failed to include header extension_messages.h"
  4533. +#endif
  4534. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  4535. new file mode 100755
  4536. --- /dev/null
  4537. +++ b/components/user_scripts/common/extension_messages.cc
  4538. @@ -0,0 +1,40 @@
  4539. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4540. +// Use of this source code is governed by a BSD-style license that can be
  4541. +// found in the LICENSE file.
  4542. +
  4543. +#include "extension_messages.h"
  4544. +
  4545. +#include <stddef.h>
  4546. +
  4547. +#include <memory>
  4548. +#include <utility>
  4549. +
  4550. +#include "content/public/common/common_param_traits.h"
  4551. +
  4552. +namespace IPC {
  4553. +
  4554. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  4555. + WriteParam(m, p.type());
  4556. + WriteParam(m, p.id());
  4557. +}
  4558. +
  4559. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  4560. + base::PickleIterator* iter,
  4561. + param_type* r) {
  4562. + HostID::HostType type;
  4563. + std::string id;
  4564. + if (!ReadParam(m, iter, &type))
  4565. + return false;
  4566. + if (!ReadParam(m, iter, &id))
  4567. + return false;
  4568. + *r = HostID(type, id);
  4569. + return true;
  4570. +}
  4571. +
  4572. +void ParamTraits<HostID>::Log(
  4573. + const param_type& p, std::string* l) {
  4574. + LogParam(p.type(), l);
  4575. + LogParam(p.id(), l);
  4576. +}
  4577. +
  4578. +} // namespace IPC
  4579. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  4580. new file mode 100755
  4581. --- /dev/null
  4582. +++ b/components/user_scripts/common/extension_messages.h
  4583. @@ -0,0 +1,70 @@
  4584. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4585. +// Use of this source code is governed by a BSD-style license that can be
  4586. +// found in the LICENSE file.
  4587. +
  4588. +// IPC messages for extensions.
  4589. +
  4590. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4591. +#define USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4592. +
  4593. +#include <stdint.h>
  4594. +
  4595. +#include <map>
  4596. +#include <memory>
  4597. +#include <set>
  4598. +#include <string>
  4599. +#include <vector>
  4600. +
  4601. +#include "base/memory/read_only_shared_memory_region.h"
  4602. +#include "base/values.h"
  4603. +#include "content/public/common/common_param_traits.h"
  4604. +#include "constants.h"
  4605. +#include "host_id.h"
  4606. +#include "ipc/ipc_message_start.h"
  4607. +#include "ipc/ipc_message_macros.h"
  4608. +#include "url/gurl.h"
  4609. +#include "url/origin.h"
  4610. +
  4611. +#define IPC_MESSAGE_START ExtensionMsgStart
  4612. +
  4613. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  4614. +
  4615. +// Singly-included section for custom IPC traits.
  4616. +#ifndef INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4617. +#define INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4618. +
  4619. +namespace IPC {
  4620. +
  4621. +template <>
  4622. +struct ParamTraits<HostID> {
  4623. + typedef HostID param_type;
  4624. + static void Write(base::Pickle* m, const param_type& p);
  4625. + static bool Read(const base::Pickle* m,
  4626. + base::PickleIterator* iter,
  4627. + param_type* r);
  4628. + static void Log(const param_type& p, std::string* l);
  4629. +};
  4630. +
  4631. +
  4632. +} // namespace IPC
  4633. +
  4634. +#endif // INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4635. +
  4636. +// Notification that the user scripts have been updated. It has one
  4637. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  4638. +// This memory region is valid in the context of the renderer.
  4639. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  4640. +// programmatically-defined scripts. Otherwise, the handle refers to all
  4641. +// hosts' statically defined scripts. So far, only extension-hosts support
  4642. +// statically defined scripts; WebUI-hosts don't.
  4643. +// If |changed_hosts| is not empty, only the host in that set will
  4644. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  4645. +// region will be updated. Note that the empty set => all hosts case is not
  4646. +// supported for per-extension programmatically-defined script regions; in such
  4647. +// regions, the owner is expected to list itself as the only changed host.
  4648. +// If |whitelisted_only| is true, this process should only run whitelisted
  4649. +// scripts and not all user scripts.
  4650. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  4651. + base::ReadOnlySharedMemoryRegion)
  4652. +
  4653. +#endif // USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4654. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  4655. new file mode 100755
  4656. --- /dev/null
  4657. +++ b/components/user_scripts/common/host_id.cc
  4658. @@ -0,0 +1,31 @@
  4659. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4660. +// Use of this source code is governed by a BSD-style license that can be
  4661. +// found in the LICENSE file.
  4662. +
  4663. +#include "host_id.h"
  4664. +
  4665. +#include <tuple>
  4666. +
  4667. +HostID::HostID()
  4668. + : type_(HostType::EXTENSIONS) {
  4669. +}
  4670. +
  4671. +HostID::HostID(HostType type, const std::string& id)
  4672. + : type_(type), id_(id) {
  4673. +}
  4674. +
  4675. +HostID::HostID(const HostID& host_id)
  4676. + : type_(host_id.type()),
  4677. + id_(host_id.id()) {
  4678. +}
  4679. +
  4680. +HostID::~HostID() {
  4681. +}
  4682. +
  4683. +bool HostID::operator<(const HostID& host_id) const {
  4684. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  4685. +}
  4686. +
  4687. +bool HostID::operator==(const HostID& host_id) const {
  4688. + return type_ == host_id.type_ && id_ == host_id.id_;
  4689. +}
  4690. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  4691. new file mode 100755
  4692. --- /dev/null
  4693. +++ b/components/user_scripts/common/host_id.h
  4694. @@ -0,0 +1,35 @@
  4695. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4696. +// Use of this source code is governed by a BSD-style license that can be
  4697. +// found in the LICENSE file.
  4698. +
  4699. +#ifndef USERSCRIPTS_COMMON_HOST_ID_H_
  4700. +#define USERSCRIPTS_COMMON_HOST_ID_H_
  4701. +
  4702. +#include <string>
  4703. +
  4704. +// IDs of hosts who own user scripts.
  4705. +// A HostID is immutable after creation.
  4706. +struct HostID {
  4707. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  4708. +
  4709. + HostID();
  4710. + HostID(HostType type, const std::string& id);
  4711. + HostID(const HostID& host_id);
  4712. + ~HostID();
  4713. +
  4714. + bool operator<(const HostID& host_id) const;
  4715. + bool operator==(const HostID& host_id) const;
  4716. +
  4717. + HostType type() const { return type_; }
  4718. + const std::string& id() const { return id_; }
  4719. +
  4720. + private:
  4721. + // The type of the host.
  4722. + HostType type_;
  4723. +
  4724. + // Similar to extension_id, host_id is a unique indentifier for a host,
  4725. + // e.g., an Extension or WebUI.
  4726. + std::string id_;
  4727. +};
  4728. +
  4729. +#endif // USERSCRIPTS_COMMON_HOST_ID_H_
  4730. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  4731. new file mode 100755
  4732. --- /dev/null
  4733. +++ b/components/user_scripts/common/script_constants.h
  4734. @@ -0,0 +1,33 @@
  4735. +// Copyright 2020 The Chromium Authors. All rights reserved.
  4736. +// Use of this source code is governed by a BSD-style license that can be
  4737. +// found in the LICENSE file.
  4738. +
  4739. +#ifndef USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4740. +#define USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4741. +
  4742. +namespace user_scripts {
  4743. +
  4744. +// Whether to fall back to matching the origin for frames where the URL
  4745. +// cannot be matched directly, such as those with about: or data: schemes.
  4746. +enum class MatchOriginAsFallbackBehavior {
  4747. + // Never fall back on the origin; this means scripts will never match on
  4748. + // these frames.
  4749. + kNever,
  4750. + // Match the origin only for about:-scheme frames, and then climb the frame
  4751. + // tree to find an appropriate ancestor to get a full URL (including path).
  4752. + // This is for supporting the "match_about_blank" key.
  4753. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  4754. + // and not worry about climbing the frame tree. It would be a behavior
  4755. + // change, but I wonder how many extensions it would impact in practice.
  4756. + kMatchForAboutSchemeAndClimbTree,
  4757. + // Match the origin as a fallback whenever applicable. This won't have a
  4758. + // corresponding path.
  4759. + kAlways,
  4760. +};
  4761. +
  4762. +// TODO(devlin): Move the other non-UserScript-specific constants like
  4763. +// RunLocation and InjectionType from UserScript into here.
  4764. +
  4765. +}
  4766. +
  4767. +#endif // USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4768. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  4769. new file mode 100755
  4770. --- /dev/null
  4771. +++ b/components/user_scripts/common/url_pattern.cc
  4772. @@ -0,0 +1,803 @@
  4773. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4774. +// Use of this source code is governed by a BSD-style license that can be
  4775. +// found in the LICENSE file.
  4776. +
  4777. +#include "url_pattern.h"
  4778. +
  4779. +#include <stddef.h>
  4780. +
  4781. +#include <ostream>
  4782. +
  4783. +#include "base/logging.h"
  4784. +#include "base/strings/pattern.h"
  4785. +#include "base/strings/strcat.h"
  4786. +#include "base/strings/string_number_conversions.h"
  4787. +#include "base/strings/string_piece.h"
  4788. +#include "base/strings/string_split.h"
  4789. +#include "base/strings/string_util.h"
  4790. +#include "base/strings/stringprintf.h"
  4791. +#include "content/public/common/url_constants.h"
  4792. +#include "constants.h"
  4793. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4794. +#include "net/base/url_util.h"
  4795. +#include "url/gurl.h"
  4796. +#include "url/url_util.h"
  4797. +
  4798. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4799. +
  4800. +namespace {
  4801. +
  4802. +// TODO(aa): What about more obscure schemes like javascript: ?
  4803. +// Note: keep this array in sync with kValidSchemeMasks.
  4804. +const char* const kValidSchemes[] = {
  4805. + url::kHttpScheme, url::kHttpsScheme,
  4806. + url::kFileScheme, url::kFtpScheme,
  4807. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4808. + url::kFileSystemScheme, url::kWsScheme,
  4809. + url::kWssScheme, url::kDataScheme,
  4810. + url::kUrnScheme,
  4811. +};
  4812. +
  4813. +const int kValidSchemeMasks[] = {
  4814. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4815. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4816. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4817. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4818. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4819. + URLPattern::SCHEME_URN,
  4820. +};
  4821. +
  4822. +static_assert(std::size(kValidSchemes) == std::size(kValidSchemeMasks),
  4823. + "must keep these arrays in sync");
  4824. +
  4825. +const char kParseSuccess[] = "Success.";
  4826. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4827. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4828. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4829. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4830. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4831. +const char kParseErrorEmptyPath[] = "Empty path.";
  4832. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4833. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4834. +
  4835. +// Message explaining each URLPattern::ParseResult.
  4836. +const char* const kParseResultMessages[] = {
  4837. + kParseSuccess,
  4838. + kParseErrorMissingSchemeSeparator,
  4839. + kParseErrorInvalidScheme,
  4840. + kParseErrorWrongSchemeType,
  4841. + kParseErrorEmptyHost,
  4842. + kParseErrorInvalidHostWildcard,
  4843. + kParseErrorEmptyPath,
  4844. + kParseErrorInvalidPort,
  4845. + kParseErrorInvalidHost,
  4846. +};
  4847. +
  4848. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4849. + std::size(kParseResultMessages),
  4850. + "must add message for each parse result");
  4851. +
  4852. +const char kPathSeparator[] = "/";
  4853. +
  4854. +bool IsStandardScheme(base::StringPiece scheme) {
  4855. + // "*" gets the same treatment as a standard scheme.
  4856. + if (scheme == "*")
  4857. + return true;
  4858. +
  4859. + return url::IsStandard(scheme.data(),
  4860. + url::Component(0, static_cast<int>(scheme.length())));
  4861. +}
  4862. +
  4863. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4864. + if (port == "*")
  4865. + return true;
  4866. +
  4867. + // Only accept non-wildcard ports if the scheme uses ports.
  4868. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4869. + url::PORT_UNSPECIFIED) {
  4870. + return false;
  4871. + }
  4872. +
  4873. + int parsed_port = url::PORT_UNSPECIFIED;
  4874. + if (!base::StringToInt(port, &parsed_port))
  4875. + return false;
  4876. + return (parsed_port >= 0) && (parsed_port < 65536);
  4877. +}
  4878. +
  4879. +// Returns |path| with the trailing wildcard stripped if one existed.
  4880. +//
  4881. +// The functions that rely on this (OverlapsWith and Contains) are only
  4882. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4883. +// the path will have only a single wildcard at the end. This makes figuring
  4884. +// out overlap much easier. It seems like there is probably a computer-sciency
  4885. +// way to solve the general case, but we don't need that yet.
  4886. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4887. + if (base::EndsWith(path, "*"))
  4888. + path.remove_suffix(1);
  4889. + return path;
  4890. +}
  4891. +
  4892. +// Removes trailing dot from |host_piece| if any.
  4893. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4894. + if (base::EndsWith(host_piece, "."))
  4895. + host_piece.remove_suffix(1);
  4896. + return host_piece;
  4897. +}
  4898. +
  4899. +} // namespace
  4900. +
  4901. +// static
  4902. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4903. + for (size_t i = 0; i < std::size(kValidSchemes); ++i) {
  4904. + if (scheme == kValidSchemes[i])
  4905. + return true;
  4906. + }
  4907. + return false;
  4908. +}
  4909. +
  4910. +// static
  4911. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4912. + int result = 0;
  4913. + for (size_t i = 0; i < std::size(kValidSchemeMasks); ++i)
  4914. + result |= kValidSchemeMasks[i];
  4915. + return result;
  4916. +}
  4917. +
  4918. +URLPattern::URLPattern()
  4919. + : valid_schemes_(SCHEME_NONE),
  4920. + match_all_urls_(false),
  4921. + match_subdomains_(false),
  4922. + port_("*") {}
  4923. +
  4924. +URLPattern::URLPattern(int valid_schemes)
  4925. + : valid_schemes_(valid_schemes),
  4926. + match_all_urls_(false),
  4927. + match_subdomains_(false),
  4928. + port_("*") {}
  4929. +
  4930. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4931. + // Strict error checking is used, because this constructor is only
  4932. + // appropriate when we know |pattern| is valid.
  4933. + : valid_schemes_(valid_schemes),
  4934. + match_all_urls_(false),
  4935. + match_subdomains_(false),
  4936. + port_("*") {
  4937. + ParseResult result = Parse(pattern);
  4938. + DCHECK_EQ(ParseResult::kSuccess, result)
  4939. + << "Parsing unexpectedly failed for pattern: " << pattern << ": "
  4940. + << GetParseResultString(result);
  4941. +}
  4942. +
  4943. +URLPattern::URLPattern(const URLPattern& other) = default;
  4944. +
  4945. +URLPattern::URLPattern(URLPattern&& other) = default;
  4946. +
  4947. +URLPattern::~URLPattern() {
  4948. +}
  4949. +
  4950. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4951. +
  4952. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4953. +
  4954. +bool URLPattern::operator<(const URLPattern& other) const {
  4955. + return GetAsString() < other.GetAsString();
  4956. +}
  4957. +
  4958. +bool URLPattern::operator>(const URLPattern& other) const {
  4959. + return GetAsString() > other.GetAsString();
  4960. +}
  4961. +
  4962. +bool URLPattern::operator==(const URLPattern& other) const {
  4963. + return GetAsString() == other.GetAsString();
  4964. +}
  4965. +
  4966. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4967. + return out << '"' << url_pattern.GetAsString() << '"';
  4968. +}
  4969. +
  4970. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  4971. + spec_.clear();
  4972. + SetMatchAllURLs(false);
  4973. + SetMatchSubdomains(false);
  4974. + SetPort("*");
  4975. +
  4976. + // Special case pattern to match every valid URL.
  4977. + if (pattern == kAllUrlsPattern) {
  4978. + SetMatchAllURLs(true);
  4979. + return ParseResult::kSuccess;
  4980. + }
  4981. +
  4982. + // Parse out the scheme.
  4983. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  4984. + bool has_standard_scheme_separator = true;
  4985. +
  4986. + // Some urls also use ':' alone as the scheme separator.
  4987. + if (scheme_end_pos == base::StringPiece::npos) {
  4988. + scheme_end_pos = pattern.find(':');
  4989. + has_standard_scheme_separator = false;
  4990. + }
  4991. +
  4992. + if (scheme_end_pos == base::StringPiece::npos)
  4993. + return ParseResult::kMissingSchemeSeparator;
  4994. +
  4995. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  4996. + return ParseResult::kInvalidScheme;
  4997. +
  4998. + bool standard_scheme = IsStandardScheme(scheme_);
  4999. + if (standard_scheme != has_standard_scheme_separator)
  5000. + return ParseResult::kWrongSchemeSeparator;
  5001. +
  5002. + // Advance past the scheme separator.
  5003. + scheme_end_pos +=
  5004. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  5005. + if (scheme_end_pos >= pattern.size())
  5006. + return ParseResult::kEmptyHost;
  5007. +
  5008. + // Parse out the host and path.
  5009. + size_t host_start_pos = scheme_end_pos;
  5010. + size_t path_start_pos = 0;
  5011. +
  5012. + if (!standard_scheme) {
  5013. + path_start_pos = host_start_pos;
  5014. + } else if (scheme_ == url::kFileScheme) {
  5015. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5016. + if (host_end_pos == base::StringPiece::npos) {
  5017. + // Allow hostname omission.
  5018. + // e.g. file://* is interpreted as file:///*,
  5019. + // file://foo* is interpreted as file:///foo*.
  5020. + path_start_pos = host_start_pos - 1;
  5021. + } else {
  5022. + // Ignore hostname if scheme is file://.
  5023. + // e.g. file://localhost/foo is equal to file:///foo.
  5024. + path_start_pos = host_end_pos;
  5025. + }
  5026. + } else {
  5027. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5028. +
  5029. + // Host is required.
  5030. + if (host_start_pos == host_end_pos)
  5031. + return ParseResult::kEmptyHost;
  5032. +
  5033. + if (host_end_pos == base::StringPiece::npos)
  5034. + return ParseResult::kEmptyPath;
  5035. +
  5036. + base::StringPiece host_and_port =
  5037. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  5038. +
  5039. + size_t port_separator_pos = base::StringPiece::npos;
  5040. + if (host_and_port[0] != '[') {
  5041. + // Not IPv6 (either IPv4 or just a normal address).
  5042. + port_separator_pos = host_and_port.find(':');
  5043. + } else { // IPv6.
  5044. + size_t host_end_pos = host_and_port.find(']');
  5045. + if (host_end_pos == base::StringPiece::npos)
  5046. + return ParseResult::kInvalidHost;
  5047. + if (host_end_pos == 1)
  5048. + return ParseResult::kEmptyHost;
  5049. +
  5050. + if (host_end_pos < host_and_port.length() - 1) {
  5051. + // The host isn't the only component. Check for a port. This would
  5052. + // require a ':' to follow the closing ']' from the host.
  5053. + if (host_and_port[host_end_pos + 1] != ':')
  5054. + return ParseResult::kInvalidHost;
  5055. +
  5056. + port_separator_pos = host_end_pos + 1;
  5057. + }
  5058. + }
  5059. +
  5060. + if (port_separator_pos != base::StringPiece::npos &&
  5061. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  5062. + return ParseResult::kInvalidPort;
  5063. + }
  5064. +
  5065. + // Note: this substr() will be the entire string if the port position
  5066. + // wasn't found.
  5067. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  5068. +
  5069. + if (host_piece.empty())
  5070. + return ParseResult::kEmptyHost;
  5071. +
  5072. + if (host_piece == "*") {
  5073. + match_subdomains_ = true;
  5074. + host_piece = base::StringPiece();
  5075. + } else if (base::StartsWith(host_piece, "*.")) {
  5076. + if (host_piece.length() == 2) {
  5077. + // We don't allow just '*.' as a host.
  5078. + return ParseResult::kEmptyHost;
  5079. + }
  5080. + match_subdomains_ = true;
  5081. + host_piece = host_piece.substr(2);
  5082. + }
  5083. +
  5084. + host_ = std::string(host_piece);
  5085. +
  5086. + path_start_pos = host_end_pos;
  5087. + }
  5088. +
  5089. + SetPath(pattern.substr(path_start_pos));
  5090. +
  5091. + // No other '*' can occur in the host, though. This isn't necessary, but is
  5092. + // done as a convenience to developers who might otherwise be confused and
  5093. + // think '*' works as a glob in the host.
  5094. + if (host_.find('*') != std::string::npos)
  5095. + return ParseResult::kInvalidHostWildcard;
  5096. +
  5097. + if (!host_.empty()) {
  5098. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  5099. + // it.
  5100. + url::CanonHostInfo host_info;
  5101. + host_ = net::CanonicalizeHost(host_, &host_info);
  5102. + // net::CanonicalizeHost() returns an empty string on failure.
  5103. + if (host_.empty())
  5104. + return ParseResult::kInvalidHost;
  5105. + }
  5106. +
  5107. + // Null characters are not allowed in hosts.
  5108. + if (host_.find('\0') != std::string::npos)
  5109. + return ParseResult::kInvalidHost;
  5110. +
  5111. + return ParseResult::kSuccess;
  5112. +}
  5113. +
  5114. +void URLPattern::SetValidSchemes(int valid_schemes) {
  5115. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  5116. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  5117. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  5118. + // http or https).
  5119. + spec_.clear();
  5120. + valid_schemes_ = valid_schemes;
  5121. +}
  5122. +
  5123. +void URLPattern::SetHost(base::StringPiece host) {
  5124. + spec_.clear();
  5125. + host_.assign(host.data(), host.size());
  5126. +}
  5127. +
  5128. +void URLPattern::SetMatchAllURLs(bool val) {
  5129. + spec_.clear();
  5130. + match_all_urls_ = val;
  5131. +
  5132. + if (val) {
  5133. + match_subdomains_ = true;
  5134. + scheme_ = "*";
  5135. + host_.clear();
  5136. + SetPath("/*");
  5137. + }
  5138. +}
  5139. +
  5140. +void URLPattern::SetMatchSubdomains(bool val) {
  5141. + spec_.clear();
  5142. + match_subdomains_ = val;
  5143. +}
  5144. +
  5145. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  5146. + spec_.clear();
  5147. + scheme_.assign(scheme.data(), scheme.size());
  5148. + if (scheme_ == "*") {
  5149. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  5150. + } else if (!IsValidScheme(scheme_)) {
  5151. + return false;
  5152. + }
  5153. + return true;
  5154. +}
  5155. +
  5156. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  5157. + if (valid_schemes_ == SCHEME_ALL)
  5158. + return true;
  5159. +
  5160. + for (size_t i = 0; i < std::size(kValidSchemes); ++i) {
  5161. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  5162. + return true;
  5163. + }
  5164. +
  5165. + return false;
  5166. +}
  5167. +
  5168. +void URLPattern::SetPath(base::StringPiece path) {
  5169. + spec_.clear();
  5170. + path_.assign(path.data(), path.size());
  5171. + path_escaped_ = path_;
  5172. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  5173. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  5174. +}
  5175. +
  5176. +bool URLPattern::SetPort(base::StringPiece port) {
  5177. + spec_.clear();
  5178. + if (IsValidPortForScheme(scheme_, port)) {
  5179. + port_.assign(port.data(), port.size());
  5180. + return true;
  5181. + }
  5182. + return false;
  5183. +}
  5184. +
  5185. +bool URLPattern::MatchesURL(const GURL& test) const {
  5186. + // Invalid URLs can never match.
  5187. + if (!test.is_valid())
  5188. + return false;
  5189. +
  5190. + const GURL* test_url = &test;
  5191. + bool has_inner_url = test.inner_url() != nullptr;
  5192. +
  5193. + if (has_inner_url) {
  5194. + if (!test.SchemeIsFileSystem())
  5195. + return false; // The only nested URLs we handle are filesystem URLs.
  5196. + test_url = test.inner_url();
  5197. + }
  5198. +
  5199. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  5200. + // the scheme is excluded.
  5201. + if (!MatchesScheme(test_url->scheme_piece()))
  5202. + return false;
  5203. +
  5204. + if (match_all_urls_)
  5205. + return true;
  5206. +
  5207. + // Unless |match_all_urls_| is true, the grammar only permits matching
  5208. + // URLs with nonempty paths.
  5209. + if (!test.has_path())
  5210. + return false;
  5211. +
  5212. + std::string path_for_request = test.PathForRequest();
  5213. + if (has_inner_url) {
  5214. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  5215. + path_for_request.c_str());
  5216. + }
  5217. +
  5218. + return MatchesSecurityOriginHelper(*test_url) &&
  5219. + MatchesPath(path_for_request);
  5220. +}
  5221. +
  5222. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  5223. + const GURL* test_url = &test;
  5224. + bool has_inner_url = test.inner_url() != NULL;
  5225. +
  5226. + if (has_inner_url) {
  5227. + if (!test.SchemeIsFileSystem())
  5228. + return false; // The only nested URLs we handle are filesystem URLs.
  5229. + test_url = test.inner_url();
  5230. + }
  5231. +
  5232. + if (!MatchesScheme(test_url->scheme()))
  5233. + return false;
  5234. +
  5235. + if (match_all_urls_)
  5236. + return true;
  5237. +
  5238. + return MatchesSecurityOriginHelper(*test_url);
  5239. +}
  5240. +
  5241. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  5242. + if (!IsValidScheme(test))
  5243. + return false;
  5244. +
  5245. + return scheme_ == "*" || test == scheme_;
  5246. +}
  5247. +
  5248. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  5249. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  5250. + // important that we do this conversion to a GURL in order to canonicalize the
  5251. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  5252. + // just do string comparison.
  5253. + return MatchesHost(
  5254. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  5255. + url::kStandardSchemeSeparator, host.data())));
  5256. +}
  5257. +
  5258. +bool URLPattern::MatchesHost(const GURL& test) const {
  5259. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  5260. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  5261. +
  5262. + // If the hosts are exactly equal, we have a match.
  5263. + if (test_host == pattern_host)
  5264. + return true;
  5265. +
  5266. + // If we're matching subdomains, and we have no host in the match pattern,
  5267. + // that means that we're matching all hosts, which means we have a match no
  5268. + // matter what the test host is.
  5269. + if (match_subdomains_ && pattern_host.empty())
  5270. + return true;
  5271. +
  5272. + // Otherwise, we can only match if our match pattern matches subdomains.
  5273. + if (!match_subdomains_)
  5274. + return false;
  5275. +
  5276. + // We don't do subdomain matching against IP addresses, so we can give up now
  5277. + // if the test host is an IP address.
  5278. + if (test.HostIsIPAddress())
  5279. + return false;
  5280. +
  5281. + // Check if the test host is a subdomain of our host.
  5282. + if (test_host.length() <= (pattern_host.length() + 1))
  5283. + return false;
  5284. +
  5285. + if (!base::EndsWith(test_host, pattern_host))
  5286. + return false;
  5287. +
  5288. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  5289. +}
  5290. +
  5291. +bool URLPattern::MatchesEffectiveTld(
  5292. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  5293. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  5294. + const {
  5295. + // Check if it matches all urls or is a pattern like http://*/*.
  5296. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  5297. + return true;
  5298. +
  5299. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  5300. + if (!match_subdomains_)
  5301. + return false;
  5302. +
  5303. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  5304. + // doesn't match all hosts in an effective TLD.
  5305. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5306. + host_, unknown_filter, private_filter)) {
  5307. + return false;
  5308. + }
  5309. +
  5310. + // At this point the host could either be just a TLD ("com") or some unknown
  5311. + // TLD-like string ("notatld"). To disambiguate between them construct a
  5312. + // fake URL, and check the registry.
  5313. + //
  5314. + // If we recognized this TLD, then this is a pattern like *.com, and it
  5315. + // matches an effective TLD.
  5316. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5317. + "notatld." + host_, unknown_filter, private_filter);
  5318. +}
  5319. +
  5320. +bool URLPattern::MatchesSingleOrigin() const {
  5321. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  5322. + // defaults to *. It's not very interesting anyway, so leave it out.
  5323. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  5324. +}
  5325. +
  5326. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  5327. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  5328. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  5329. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  5330. + if (path_escaped_.length() == test.length() + 2 &&
  5331. + base::StartsWith(path_escaped_.c_str(), test) &&
  5332. + base::EndsWith(path_escaped_, "/*")) {
  5333. + return true;
  5334. + }
  5335. +
  5336. + return base::MatchPattern(test, path_escaped_);
  5337. +}
  5338. +
  5339. +const std::string& URLPattern::GetAsString() const {
  5340. + if (!spec_.empty())
  5341. + return spec_;
  5342. +
  5343. + if (match_all_urls_) {
  5344. + spec_ = kAllUrlsPattern;
  5345. + return spec_;
  5346. + }
  5347. +
  5348. + bool standard_scheme = IsStandardScheme(scheme_);
  5349. +
  5350. + std::string spec = scheme_ +
  5351. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  5352. +
  5353. + if (scheme_ != url::kFileScheme && standard_scheme) {
  5354. + if (match_subdomains_) {
  5355. + spec += "*";
  5356. + if (!host_.empty())
  5357. + spec += ".";
  5358. + }
  5359. +
  5360. + if (!host_.empty())
  5361. + spec += host_;
  5362. +
  5363. + if (port_ != "*") {
  5364. + spec += ":";
  5365. + spec += port_;
  5366. + }
  5367. + }
  5368. +
  5369. + if (!path_.empty())
  5370. + spec += path_;
  5371. +
  5372. + spec_ = std::move(spec);
  5373. + return spec_;
  5374. +}
  5375. +
  5376. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  5377. + if (match_all_urls() || other.match_all_urls())
  5378. + return true;
  5379. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  5380. + other.MatchesAnyScheme(GetExplicitSchemes()))
  5381. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  5382. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  5383. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  5384. + other.MatchesPath(StripTrailingWildcard(path())));
  5385. +}
  5386. +
  5387. +bool URLPattern::Contains(const URLPattern& other) const {
  5388. + // Important: it's not enough to just check match_all_urls(); we also need to
  5389. + // make sure that the schemes in this pattern are a superset of those in
  5390. + // |other|.
  5391. + if (match_all_urls() &&
  5392. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  5393. + return true;
  5394. + }
  5395. +
  5396. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  5397. + MatchesHost(other.host()) &&
  5398. + (!other.match_subdomains_ || match_subdomains_) &&
  5399. + MatchesPortPattern(other.port()) &&
  5400. + MatchesPath(StripTrailingWildcard(other.path()));
  5401. +}
  5402. +
  5403. +absl::optional<URLPattern> URLPattern::CreateIntersection(
  5404. + const URLPattern& other) const {
  5405. + // Easy case: Schemes don't overlap. Return nullopt.
  5406. + int intersection_schemes = URLPattern::SCHEME_NONE;
  5407. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  5408. + intersection_schemes = other.valid_schemes_;
  5409. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  5410. + intersection_schemes = valid_schemes_;
  5411. + else
  5412. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  5413. +
  5414. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  5415. + return absl::nullopt;
  5416. +
  5417. + {
  5418. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  5419. + // This can happen when either:
  5420. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  5421. + // - One of the patterns has match_all_urls() equal to true.
  5422. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  5423. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  5424. + // from the path, which could yield the incorrect result.
  5425. + const URLPattern* copy_source = nullptr;
  5426. + if (*this == other || other.match_all_urls())
  5427. + copy_source = this;
  5428. + else if (match_all_urls())
  5429. + copy_source = &other;
  5430. +
  5431. + if (copy_source) {
  5432. + // NOTE: equality checks don't take into account valid_schemes_, and
  5433. + // schemes can be different in the case of match_all_urls() as well, so
  5434. + // we can't always just return *copy_source.
  5435. + if (intersection_schemes == copy_source->valid_schemes_)
  5436. + return *copy_source;
  5437. + URLPattern result(intersection_schemes);
  5438. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  5439. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  5440. + return result;
  5441. + }
  5442. + }
  5443. +
  5444. + // No more easy cases. Go through component by component to find the patterns
  5445. + // that intersect.
  5446. +
  5447. + // Note: Alias the function type (rather than using auto) because
  5448. + // MatchesHost() is overloaded.
  5449. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  5450. +
  5451. + auto get_intersection = [this, &other](base::StringPiece own_str,
  5452. + base::StringPiece other_str,
  5453. + match_function_type match_function,
  5454. + base::StringPiece* out) {
  5455. + if ((this->*match_function)(other_str)) {
  5456. + *out = other_str;
  5457. + return true;
  5458. + }
  5459. + if ((other.*match_function)(own_str)) {
  5460. + *out = own_str;
  5461. + return true;
  5462. + }
  5463. + return false;
  5464. + };
  5465. +
  5466. + base::StringPiece scheme;
  5467. + base::StringPiece host;
  5468. + base::StringPiece port;
  5469. + base::StringPiece path;
  5470. + // If any pieces fail to overlap, then there is no intersection.
  5471. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  5472. + &scheme) ||
  5473. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  5474. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  5475. + &port) ||
  5476. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  5477. + return absl::nullopt;
  5478. + }
  5479. +
  5480. + // Only match subdomains if both patterns match subdomains.
  5481. + base::StringPiece subdomains;
  5482. + if (match_subdomains_ && other.match_subdomains_) {
  5483. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  5484. + // append '*' instead of '*.'.
  5485. + subdomains = host.empty() ? "*" : "*.";
  5486. + }
  5487. +
  5488. + base::StringPiece scheme_separator =
  5489. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  5490. +
  5491. + std::string pattern_str = base::StrCat(
  5492. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  5493. +
  5494. + URLPattern pattern(intersection_schemes);
  5495. + ParseResult result = pattern.Parse(pattern_str);
  5496. + // TODO(devlin): I don't think there's any way this should ever fail, but
  5497. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  5498. + // to a DCHECK in M72.
  5499. + CHECK_EQ(ParseResult::kSuccess, result);
  5500. +
  5501. + return pattern;
  5502. +}
  5503. +
  5504. +bool URLPattern::MatchesAnyScheme(
  5505. + const std::vector<std::string>& schemes) const {
  5506. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5507. + if (MatchesScheme(*i))
  5508. + return true;
  5509. + }
  5510. +
  5511. + return false;
  5512. +}
  5513. +
  5514. +bool URLPattern::MatchesAllSchemes(
  5515. + const std::vector<std::string>& schemes) const {
  5516. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5517. + if (!MatchesScheme(*i))
  5518. + return false;
  5519. + }
  5520. +
  5521. + return true;
  5522. +}
  5523. +
  5524. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  5525. + // Ignore hostname if scheme is file://.
  5526. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  5527. + return false;
  5528. +
  5529. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  5530. + return false;
  5531. +
  5532. + return true;
  5533. +}
  5534. +
  5535. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  5536. + return port_ == "*" || port_ == port;
  5537. +}
  5538. +
  5539. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  5540. + std::vector<std::string> result;
  5541. +
  5542. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  5543. + result.push_back(scheme_);
  5544. + return result;
  5545. + }
  5546. +
  5547. + for (size_t i = 0; i < std::size(kValidSchemes); ++i) {
  5548. + if (MatchesScheme(kValidSchemes[i])) {
  5549. + result.push_back(kValidSchemes[i]);
  5550. + }
  5551. + }
  5552. +
  5553. + return result;
  5554. +}
  5555. +
  5556. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  5557. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  5558. + std::vector<URLPattern> result;
  5559. +
  5560. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  5561. + i != explicit_schemes.end(); ++i) {
  5562. + URLPattern temp = *this;
  5563. + temp.SetScheme(*i);
  5564. + temp.SetMatchAllURLs(false);
  5565. + result.push_back(temp);
  5566. + }
  5567. +
  5568. + return result;
  5569. +}
  5570. +
  5571. +// static
  5572. +const char* URLPattern::GetParseResultString(
  5573. + URLPattern::ParseResult parse_result) {
  5574. + return kParseResultMessages[static_cast<int>(parse_result)];
  5575. +}
  5576. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  5577. new file mode 100755
  5578. --- /dev/null
  5579. +++ b/components/user_scripts/common/url_pattern.h
  5580. @@ -0,0 +1,302 @@
  5581. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5582. +// Use of this source code is governed by a BSD-style license that can be
  5583. +// found in the LICENSE file.
  5584. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_H_
  5585. +#define USERSCRIPTS_COMMON_URL_PATTERN_H_
  5586. +
  5587. +#include <functional>
  5588. +#include <iosfwd>
  5589. +#include <string>
  5590. +#include <vector>
  5591. +
  5592. +#include "base/strings/string_piece.h"
  5593. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  5594. +
  5595. +class GURL;
  5596. +
  5597. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  5598. +// subset of URL syntax:
  5599. +//
  5600. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  5601. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  5602. +// 'chrome-extension' | 'filesystem'
  5603. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  5604. +// '*.' <anychar except '/' and '*'>+
  5605. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  5606. +// <path> := '/' <any chars>
  5607. +//
  5608. +// * Host is not used when the scheme is 'file'.
  5609. +// * The path can have embedded '*' characters which act as glob wildcards.
  5610. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  5611. +// a valid scheme (as specified by valid_schemes_).
  5612. +// * The '*' scheme pattern excludes file URLs.
  5613. +//
  5614. +// Examples of valid patterns:
  5615. +// - http://*/*
  5616. +// - http://*/foo*
  5617. +// - https://*.google.com/foo*bar
  5618. +// - file://monkey*
  5619. +// - http://127.0.0.1/*
  5620. +// - http://[2607:f8b0:4005:805::200e]/*
  5621. +//
  5622. +// Examples of invalid patterns:
  5623. +// - http://* -- path not specified
  5624. +// - http://*foo/bar -- * not allowed as substring of host component
  5625. +// - http://foo.*.bar/baz -- * must be first component
  5626. +// - http:/bar -- scheme separator not found
  5627. +// - foo://* -- invalid scheme
  5628. +// - chrome:// -- we don't support chrome internal URLs
  5629. +class URLPattern {
  5630. + public:
  5631. + // A collection of scheme bitmasks for use with valid_schemes.
  5632. + enum SchemeMasks {
  5633. + SCHEME_NONE = 0,
  5634. + SCHEME_HTTP = 1 << 0,
  5635. + SCHEME_HTTPS = 1 << 1,
  5636. + SCHEME_FILE = 1 << 2,
  5637. + SCHEME_FTP = 1 << 3,
  5638. + SCHEME_CHROMEUI = 1 << 4,
  5639. + SCHEME_EXTENSION = 1 << 5,
  5640. + SCHEME_FILESYSTEM = 1 << 6,
  5641. + SCHEME_WS = 1 << 7,
  5642. + SCHEME_WSS = 1 << 8,
  5643. + SCHEME_DATA = 1 << 9,
  5644. + SCHEME_URN = 1 << 10,
  5645. +
  5646. + // IMPORTANT!
  5647. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  5648. + // extension://, about:, etc. Because this has lots of security
  5649. + // implications, third-party extensions should usually not be able to get
  5650. + // access to URL patterns initialized this way. If there is a reason
  5651. + // for violating this general rule, document why this it safe.
  5652. + SCHEME_ALL = -1,
  5653. + };
  5654. +
  5655. + // Error codes returned from Parse().
  5656. + enum class ParseResult {
  5657. + kSuccess = 0,
  5658. + kMissingSchemeSeparator,
  5659. + kInvalidScheme,
  5660. + kWrongSchemeSeparator,
  5661. + kEmptyHost,
  5662. + kInvalidHostWildcard,
  5663. + kEmptyPath,
  5664. + kInvalidPort,
  5665. + kInvalidHost,
  5666. + kNumParseResults,
  5667. + };
  5668. +
  5669. + // The <all_urls> string pattern.
  5670. + static const char kAllUrlsPattern[];
  5671. +
  5672. + // Returns true if the given |scheme| is considered valid for extensions.
  5673. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  5674. +
  5675. + // Returns the mask for all schemes considered valid for extensions.
  5676. + static int GetValidSchemeMaskForExtensions();
  5677. +
  5678. + explicit URLPattern(int valid_schemes);
  5679. +
  5680. + // Convenience to construct a URLPattern from a string. If the string is not
  5681. + // known ahead of time, use Parse() instead, which returns success or failure.
  5682. + URLPattern(int valid_schemes, base::StringPiece pattern);
  5683. +
  5684. + URLPattern();
  5685. + URLPattern(const URLPattern& other);
  5686. + URLPattern(URLPattern&& other);
  5687. + ~URLPattern();
  5688. +
  5689. + URLPattern& operator=(const URLPattern& other);
  5690. + URLPattern& operator=(URLPattern&& other);
  5691. +
  5692. + bool operator<(const URLPattern& other) const;
  5693. + bool operator>(const URLPattern& other) const;
  5694. + bool operator==(const URLPattern& other) const;
  5695. +
  5696. + // Initializes this instance by parsing the provided string. Returns
  5697. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  5698. + // On failure, this instance will have some intermediate values and is in an
  5699. + // invalid state.
  5700. + ParseResult Parse(base::StringPiece pattern_str);
  5701. +
  5702. + // Gets the bitmask of valid schemes.
  5703. + int valid_schemes() const { return valid_schemes_; }
  5704. + void SetValidSchemes(int valid_schemes);
  5705. +
  5706. + // Gets the host the pattern matches. This can be an empty string if the
  5707. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  5708. + const std::string& host() const { return host_; }
  5709. + void SetHost(base::StringPiece host);
  5710. +
  5711. + // Gets whether to match subdomains of host().
  5712. + bool match_subdomains() const { return match_subdomains_; }
  5713. + void SetMatchSubdomains(bool val);
  5714. +
  5715. + // Gets the path the pattern matches with the leading slash. This can have
  5716. + // embedded asterisks which are interpreted using glob rules.
  5717. + const std::string& path() const { return path_; }
  5718. + void SetPath(base::StringPiece path);
  5719. +
  5720. + // Returns true if this pattern matches all (valid) urls.
  5721. + bool match_all_urls() const { return match_all_urls_; }
  5722. + void SetMatchAllURLs(bool val);
  5723. +
  5724. + // Sets the scheme for pattern matches. This can be a single '*' if the
  5725. + // pattern matches all valid schemes (as defined by the valid_schemes_
  5726. + // property). Returns false on failure (if the scheme is not valid).
  5727. + bool SetScheme(base::StringPiece scheme);
  5728. + // Note: You should use MatchesScheme() instead of this getter unless you
  5729. + // absolutely need the exact scheme. This is exposed for testing.
  5730. + const std::string& scheme() const { return scheme_; }
  5731. +
  5732. + // Returns true if the specified scheme can be used in this URL pattern, and
  5733. + // false otherwise. Uses valid_schemes_ to determine validity.
  5734. + bool IsValidScheme(base::StringPiece scheme) const;
  5735. +
  5736. + // Returns true if this instance matches the specified URL. Always returns
  5737. + // false for invalid URLs.
  5738. + bool MatchesURL(const GURL& test) const;
  5739. +
  5740. + // Returns true if this instance matches the specified security origin.
  5741. + bool MatchesSecurityOrigin(const GURL& test) const;
  5742. +
  5743. + // Returns true if |test| matches our scheme.
  5744. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  5745. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  5746. + // of the outer "filesystem:" part.
  5747. + bool MatchesScheme(base::StringPiece test) const;
  5748. +
  5749. + // Returns true if |test| matches our host.
  5750. + bool MatchesHost(base::StringPiece test) const;
  5751. + bool MatchesHost(const GURL& test) const;
  5752. +
  5753. + // Returns true if |test| matches our path.
  5754. + bool MatchesPath(base::StringPiece test) const;
  5755. +
  5756. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  5757. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  5758. + // matches all domains (e.g., *://*/*) will return true.
  5759. + // |private_filter| specifies whether private registries (like appspot.com)
  5760. + // should be considered; if included, patterns like *://*.appspot.com/* will
  5761. + // return true. By default, we exclude private registries (so *.appspot.com
  5762. + // returns false).
  5763. + // Note: This is an expensive method, and should be used sparingly!
  5764. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  5765. + // cached.
  5766. + bool MatchesEffectiveTld(
  5767. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  5768. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  5769. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  5770. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  5771. +
  5772. + // Returns true if the pattern only matches a single origin. The pattern may
  5773. + // include a path.
  5774. + bool MatchesSingleOrigin() const;
  5775. +
  5776. + // Sets the port. Returns false if the port is invalid.
  5777. + bool SetPort(base::StringPiece port);
  5778. + const std::string& port() const { return port_; }
  5779. +
  5780. + // Returns a string representing this instance.
  5781. + const std::string& GetAsString() const;
  5782. +
  5783. + // Determines whether there is a URL that would match this instance and
  5784. + // another instance. This method is symmetrical: Calling
  5785. + // other.OverlapsWith(this) would result in the same answer.
  5786. + bool OverlapsWith(const URLPattern& other) const;
  5787. +
  5788. + // Returns true if this pattern matches all possible URLs that |other| can
  5789. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5790. + bool Contains(const URLPattern& other) const;
  5791. +
  5792. + // Creates a new URLPattern that represents the intersection of this
  5793. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5794. + // For instance, given the patterns http://*.google.com/* and
  5795. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5796. + // NOTES:
  5797. + // - Though scheme intersections are supported, the serialization of
  5798. + // URLPatternSet does not record them. Be sure that this is safe for your
  5799. + // use cases.
  5800. + // - Path intersection is done on a best-effort basis. If one path clearly
  5801. + // contains another, it will be handled correctly, but this method does not
  5802. + // deal with cases like /*a* and /*b* (where technically the intersection
  5803. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5804. + absl::optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5805. +
  5806. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5807. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5808. + // wildcard scheme, then the returned set will contain one element that is
  5809. + // equivalent to this instance.
  5810. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5811. +
  5812. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5813. + if (a.match_all_urls_ && b.match_all_urls_)
  5814. + return false;
  5815. + return a.host_.compare(b.host_) < 0;
  5816. + }
  5817. +
  5818. + // Used for origin comparisons in a std::set.
  5819. + class EffectiveHostCompareFunctor {
  5820. + public:
  5821. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5822. + return EffectiveHostCompare(a, b);
  5823. + }
  5824. + };
  5825. +
  5826. + // Get an error string for a ParseResult.
  5827. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5828. +
  5829. + private:
  5830. + // Returns true if any of the |schemes| items matches our scheme.
  5831. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5832. +
  5833. + // Returns true if all of the |schemes| items matches our scheme.
  5834. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5835. +
  5836. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5837. +
  5838. + // Returns true if our port matches the |port| pattern (it may be "*").
  5839. + bool MatchesPortPattern(base::StringPiece port) const;
  5840. +
  5841. + // If the URLPattern contains a wildcard scheme, returns a list of
  5842. + // equivalent literal schemes, otherwise returns the current scheme.
  5843. + std::vector<std::string> GetExplicitSchemes() const;
  5844. +
  5845. + // A bitmask containing the schemes which are considered valid for this
  5846. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5847. + // scheme.
  5848. + int valid_schemes_;
  5849. +
  5850. + // True if this is a special-case "<all_urls>" pattern.
  5851. + bool match_all_urls_;
  5852. +
  5853. + // The scheme for the pattern.
  5854. + std::string scheme_;
  5855. +
  5856. + // The host without any leading "*" components.
  5857. + std::string host_;
  5858. +
  5859. + // Whether we should match subdomains of the host. This is true if the first
  5860. + // component of the pattern's host was "*".
  5861. + bool match_subdomains_;
  5862. +
  5863. + // The port.
  5864. + std::string port_;
  5865. +
  5866. + // The path to match. This is everything after the host of the URL, or
  5867. + // everything after the scheme in the case of file:// URLs.
  5868. + std::string path_;
  5869. +
  5870. + // The path with "?" and "\" characters escaped for use with the
  5871. + // MatchPattern() function.
  5872. + std::string path_escaped_;
  5873. +
  5874. + // A string representing this URLPattern.
  5875. + mutable std::string spec_;
  5876. +};
  5877. +
  5878. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5879. +
  5880. +typedef std::vector<URLPattern> URLPatternList;
  5881. +
  5882. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_H_
  5883. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5884. new file mode 100755
  5885. --- /dev/null
  5886. +++ b/components/user_scripts/common/url_pattern_set.cc
  5887. @@ -0,0 +1,335 @@
  5888. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5889. +// Use of this source code is governed by a BSD-style license that can be
  5890. +// found in the LICENSE file.
  5891. +
  5892. +#include "url_pattern_set.h"
  5893. +
  5894. +#include <iterator>
  5895. +#include <ostream>
  5896. +
  5897. +#include "base/containers/contains.h"
  5898. +#include "base/logging.h"
  5899. +#include "base/stl_util.h"
  5900. +#include "base/values.h"
  5901. +#include "error_utils.h"
  5902. +#include "url_pattern.h"
  5903. +#include "url/gurl.h"
  5904. +#include "url/origin.h"
  5905. +#include "url/url_constants.h"
  5906. +#include "user_scripts_features.h"
  5907. +
  5908. +namespace user_scripts {
  5909. +
  5910. +namespace {
  5911. +
  5912. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5913. +
  5914. +} // namespace
  5915. +
  5916. +// static
  5917. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5918. + const URLPatternSet& set2) {
  5919. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5920. + set1.patterns_, set2.patterns_));
  5921. +}
  5922. +
  5923. +// static
  5924. +URLPatternSet URLPatternSet::CreateIntersection(
  5925. + const URLPatternSet& set1,
  5926. + const URLPatternSet& set2,
  5927. + IntersectionBehavior intersection_behavior) {
  5928. + // Note: leverage return value optimization; always return the same object.
  5929. + URLPatternSet result;
  5930. +
  5931. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5932. + // String comparison just relies on STL set behavior, which looks at the
  5933. + // string representation.
  5934. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5935. + set1.patterns_, set2.patterns_));
  5936. + return result;
  5937. + }
  5938. +
  5939. + // Look for a semantic intersection.
  5940. +
  5941. + // Step 1: Iterate over each set. Find any patterns that are completely
  5942. + // contained by the other (thus being necessarily present in any intersection)
  5943. + // and add them, collecting the others in a set of unique items.
  5944. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5945. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5946. + // const, this should be safe.
  5947. + std::vector<const URLPattern*> unique_set1;
  5948. + for (const URLPattern& pattern : set1) {
  5949. + if (set2.ContainsPattern(pattern))
  5950. + result.patterns_.insert(pattern);
  5951. + else
  5952. + unique_set1.push_back(&pattern);
  5953. + }
  5954. + std::vector<const URLPattern*> unique_set2;
  5955. + for (const URLPattern& pattern : set2) {
  5956. + if (set1.ContainsPattern(pattern))
  5957. + result.patterns_.insert(pattern);
  5958. + else
  5959. + unique_set2.push_back(&pattern);
  5960. + }
  5961. +
  5962. + // If we're just looking for patterns contained by both, we're done.
  5963. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5964. + return result;
  5965. +
  5966. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5967. +
  5968. + // Step 2: Iterate over all the unique patterns and find the intersections
  5969. + // they have with the other patterns.
  5970. + for (const auto* pattern : unique_set1) {
  5971. + for (const auto* pattern2 : unique_set2) {
  5972. + absl::optional<URLPattern> intersection =
  5973. + pattern->CreateIntersection(*pattern2);
  5974. + if (intersection)
  5975. + result.patterns_.insert(std::move(*intersection));
  5976. + }
  5977. + }
  5978. +
  5979. + return result;
  5980. +}
  5981. +
  5982. +// static
  5983. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  5984. + const URLPatternSet& set2) {
  5985. + return URLPatternSet(
  5986. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  5987. +}
  5988. +
  5989. +// static
  5990. +URLPatternSet URLPatternSet::CreateUnion(
  5991. + const std::vector<URLPatternSet>& sets) {
  5992. + URLPatternSet result;
  5993. + if (sets.empty())
  5994. + return result;
  5995. +
  5996. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  5997. + //
  5998. + // Do the first merge step into a working set so that we don't mutate any of
  5999. + // the input.
  6000. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  6001. + // clean that up.
  6002. + std::vector<URLPatternSet> working;
  6003. + for (size_t i = 0; i < sets.size(); i += 2) {
  6004. + if (i + 1 < sets.size())
  6005. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  6006. + else
  6007. + working.push_back(sets[i].Clone());
  6008. + }
  6009. +
  6010. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  6011. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  6012. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  6013. + working[i].patterns_.swap(u.patterns_);
  6014. + }
  6015. + }
  6016. +
  6017. + result.patterns_.swap(working[0].patterns_);
  6018. + return result;
  6019. +}
  6020. +
  6021. +URLPatternSet::URLPatternSet() = default;
  6022. +
  6023. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  6024. +
  6025. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  6026. + : patterns_(patterns) {}
  6027. +
  6028. +URLPatternSet::~URLPatternSet() = default;
  6029. +
  6030. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  6031. +
  6032. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  6033. + return patterns_ == other.patterns_;
  6034. +}
  6035. +
  6036. +std::ostream& operator<<(std::ostream& out,
  6037. + const URLPatternSet& url_pattern_set) {
  6038. + out << "{ ";
  6039. +
  6040. + auto iter = url_pattern_set.patterns().cbegin();
  6041. + if (!url_pattern_set.patterns().empty()) {
  6042. + out << *iter;
  6043. + ++iter;
  6044. + }
  6045. +
  6046. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  6047. + out << ", " << *iter;
  6048. +
  6049. + if (!url_pattern_set.patterns().empty())
  6050. + out << " ";
  6051. +
  6052. + out << "}";
  6053. + return out;
  6054. +}
  6055. +
  6056. +URLPatternSet URLPatternSet::Clone() const {
  6057. + return URLPatternSet(patterns_);
  6058. +}
  6059. +
  6060. +bool URLPatternSet::is_empty() const {
  6061. + return patterns_.empty();
  6062. +}
  6063. +
  6064. +size_t URLPatternSet::size() const {
  6065. + return patterns_.size();
  6066. +}
  6067. +
  6068. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  6069. + return patterns_.insert(pattern).second;
  6070. +}
  6071. +
  6072. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  6073. + patterns_.insert(set.patterns().begin(),
  6074. + set.patterns().end());
  6075. +}
  6076. +
  6077. +void URLPatternSet::ClearPatterns() {
  6078. + patterns_.clear();
  6079. +}
  6080. +
  6081. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  6082. + if (origin.is_empty())
  6083. + return false;
  6084. + const url::Origin real_origin = url::Origin::Create(origin);
  6085. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(
  6086. + origin.DeprecatedGetOriginAsURL())));
  6087. + URLPattern origin_pattern(valid_schemes);
  6088. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  6089. + if (origin_pattern.Parse(origin.spec()) !=
  6090. + URLPattern::ParseResult::kSuccess) {
  6091. + return false;
  6092. + }
  6093. + origin_pattern.SetPath("/*");
  6094. + return AddPattern(origin_pattern);
  6095. +}
  6096. +
  6097. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  6098. + for (auto it = other.begin(); it != other.end(); ++it) {
  6099. + if (!ContainsPattern(*it))
  6100. + return false;
  6101. + }
  6102. +
  6103. + return true;
  6104. +}
  6105. +
  6106. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  6107. + for (auto it = begin(); it != end(); ++it) {
  6108. + if (it->Contains(pattern))
  6109. + return true;
  6110. + }
  6111. + return false;
  6112. +}
  6113. +
  6114. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  6115. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  6116. + ++pattern) {
  6117. + if (pattern->MatchesURL(url)) {
  6118. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6119. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  6120. +
  6121. + return true;
  6122. + }
  6123. + }
  6124. +
  6125. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6126. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  6127. +
  6128. + return false;
  6129. +}
  6130. +
  6131. +bool URLPatternSet::MatchesAllURLs() const {
  6132. + for (auto host = begin(); host != end(); ++host) {
  6133. + if (host->match_all_urls() ||
  6134. + (host->match_subdomains() && host->host().empty()))
  6135. + return true;
  6136. + }
  6137. + return false;
  6138. +}
  6139. +
  6140. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  6141. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  6142. + ++pattern) {
  6143. + if (pattern->MatchesSecurityOrigin(origin))
  6144. + return true;
  6145. + }
  6146. +
  6147. + return false;
  6148. +}
  6149. +
  6150. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  6151. + // Two extension extents overlap if there is any one URL that would match at
  6152. + // least one pattern in each of the extents.
  6153. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6154. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  6155. + ++j) {
  6156. + if (i->OverlapsWith(*j))
  6157. + return true;
  6158. + }
  6159. + }
  6160. +
  6161. + return false;
  6162. +}
  6163. +
  6164. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  6165. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  6166. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6167. + base::Value pattern_str_value(i->GetAsString());
  6168. + if (!base::Contains(value->GetList(), pattern_str_value))
  6169. + value->Append(std::move(pattern_str_value));
  6170. + }
  6171. + return value;
  6172. +}
  6173. +
  6174. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  6175. + int valid_schemes,
  6176. + bool allow_file_access,
  6177. + std::string* error) {
  6178. + ClearPatterns();
  6179. + for (size_t i = 0; i < patterns.size(); ++i) {
  6180. + URLPattern pattern(valid_schemes);
  6181. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  6182. + if (error) {
  6183. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  6184. + patterns[i]);
  6185. + } else {
  6186. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  6187. + }
  6188. + return false;
  6189. + }
  6190. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  6191. + pattern.SetValidSchemes(
  6192. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  6193. + }
  6194. + AddPattern(pattern);
  6195. + }
  6196. + return true;
  6197. +}
  6198. +
  6199. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  6200. + const {
  6201. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  6202. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6203. + value->push_back(i->GetAsString());
  6204. + }
  6205. + return value;
  6206. +}
  6207. +
  6208. +bool URLPatternSet::Populate(const base::ListValue& value,
  6209. + int valid_schemes,
  6210. + bool allow_file_access,
  6211. + std::string* error) {
  6212. + std::vector<std::string> patterns;
  6213. + for (const base::Value& pattern : value.GetList()) {
  6214. + const std::string* item = pattern.GetIfString();
  6215. + if (!item)
  6216. + return false;
  6217. + patterns.push_back(*item);
  6218. + }
  6219. + return Populate(patterns, valid_schemes, allow_file_access, error);
  6220. +}
  6221. +
  6222. +} // namespace extensions
  6223. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  6224. new file mode 100755
  6225. --- /dev/null
  6226. +++ b/components/user_scripts/common/url_pattern_set.h
  6227. @@ -0,0 +1,160 @@
  6228. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6229. +// Use of this source code is governed by a BSD-style license that can be
  6230. +// found in the LICENSE file.
  6231. +
  6232. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6233. +#define USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6234. +
  6235. +#include <stddef.h>
  6236. +
  6237. +#include <iosfwd>
  6238. +#include <memory>
  6239. +#include <set>
  6240. +
  6241. +#include "url_pattern.h"
  6242. +
  6243. +class GURL;
  6244. +
  6245. +namespace base {
  6246. +class ListValue;
  6247. +class Value;
  6248. +}
  6249. +
  6250. +namespace user_scripts {
  6251. +
  6252. +// Represents the set of URLs an extension uses for web content.
  6253. +class URLPatternSet {
  6254. + public:
  6255. + URLPatternSet(const URLPatternSet&) = delete;
  6256. + URLPatternSet& operator=(const URLPatternSet&) = delete;
  6257. + typedef std::set<URLPattern>::const_iterator const_iterator;
  6258. + typedef std::set<URLPattern>::iterator iterator;
  6259. +
  6260. + // Returns |set1| - |set2|.
  6261. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  6262. + const URLPatternSet& set2);
  6263. +
  6264. + enum class IntersectionBehavior {
  6265. + // For the following descriptions, consider the two URLPatternSets:
  6266. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  6267. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  6268. + // "*://chromium.org/*"}
  6269. +
  6270. + // Only includes patterns that are exactly in both sets. The intersection of
  6271. + // the two sets above is {"https://example.com/*"}, since that is the only
  6272. + // pattern that appears exactly in each.
  6273. + kStringComparison,
  6274. +
  6275. + // Includes patterns that are effectively contained by both sets. The
  6276. + // intersection of the two sets above is
  6277. + // {
  6278. + // "https://example.com/*" (contained exactly by each set)
  6279. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6280. + // subset of https://*.google.com/* in set 1)
  6281. + // }
  6282. + kPatternsContainedByBoth,
  6283. +
  6284. + // Includes patterns that are contained by both sets and creates new
  6285. + // patterns to represent the intersection of any others. The intersection of
  6286. + // the two sets above is
  6287. + // {
  6288. + // "https://example.com/*" (contained exactly by each set)
  6289. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6290. + // subset of https://*.google.com/* in set 1)
  6291. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  6292. + // *://chromium.org/*" in set 2).
  6293. + // }
  6294. + // Note that this is the most computationally expensive - potentially
  6295. + // O(n^2) - since it can require comparing each pattern in one set to every
  6296. + // pattern in the other set.
  6297. + kDetailed,
  6298. + };
  6299. +
  6300. + // Returns the intersection of |set1| and |set2| according to
  6301. + // |intersection_behavior|.
  6302. + static URLPatternSet CreateIntersection(
  6303. + const URLPatternSet& set1,
  6304. + const URLPatternSet& set2,
  6305. + IntersectionBehavior intersection_behavior);
  6306. +
  6307. + // Returns the union of |set1| and |set2|.
  6308. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  6309. + const URLPatternSet& set2);
  6310. +
  6311. + // Returns the union of all sets in |sets|.
  6312. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  6313. +
  6314. + URLPatternSet();
  6315. + URLPatternSet(URLPatternSet&& rhs);
  6316. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  6317. + ~URLPatternSet();
  6318. +
  6319. + URLPatternSet& operator=(URLPatternSet&& rhs);
  6320. + bool operator==(const URLPatternSet& rhs) const;
  6321. +
  6322. + bool is_empty() const;
  6323. + size_t size() const;
  6324. + const std::set<URLPattern>& patterns() const { return patterns_; }
  6325. + const_iterator begin() const { return patterns_.begin(); }
  6326. + const_iterator end() const { return patterns_.end(); }
  6327. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  6328. +
  6329. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  6330. + // constructor to avoid accidental/unnecessary copies.
  6331. + URLPatternSet Clone() const;
  6332. +
  6333. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  6334. + // false if the pattern was already in the set.
  6335. + bool AddPattern(const URLPattern& pattern);
  6336. +
  6337. + // Adds all patterns from |set| into this.
  6338. + void AddPatterns(const URLPatternSet& set);
  6339. +
  6340. + void ClearPatterns();
  6341. +
  6342. + // Adds a pattern based on |origin| to the set.
  6343. + bool AddOrigin(int valid_schemes, const GURL& origin);
  6344. +
  6345. + // Returns true if every URL that matches |set| is matched by this. In other
  6346. + // words, if every pattern in |set| is encompassed by a pattern in this.
  6347. + bool Contains(const URLPatternSet& set) const;
  6348. +
  6349. + // Returns true if any pattern in this set encompasses |pattern|.
  6350. + bool ContainsPattern(const URLPattern& pattern) const;
  6351. +
  6352. + // Test if the extent contains a URL.
  6353. + bool MatchesURL(const GURL& url) const;
  6354. +
  6355. + // Test if the extent matches all URLs (for example, <all_urls>).
  6356. + bool MatchesAllURLs() const;
  6357. +
  6358. + bool MatchesSecurityOrigin(const GURL& origin) const;
  6359. +
  6360. + // Returns true if there is a single URL that would be in two extents.
  6361. + bool OverlapsWith(const URLPatternSet& other) const;
  6362. +
  6363. + // Converts to and from Value for serialization to preferences.
  6364. + std::unique_ptr<base::ListValue> ToValue() const;
  6365. + bool Populate(const base::ListValue& value,
  6366. + int valid_schemes,
  6367. + bool allow_file_access,
  6368. + std::string* error);
  6369. +
  6370. + // Converts to and from a vector of strings.
  6371. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  6372. + bool Populate(const std::vector<std::string>& patterns,
  6373. + int valid_schemes,
  6374. + bool allow_file_access,
  6375. + std::string* error);
  6376. +
  6377. + private:
  6378. + // The list of URL patterns that comprise the extent.
  6379. + std::set<URLPattern> patterns_;
  6380. +};
  6381. +
  6382. +std::ostream& operator<<(std::ostream& out,
  6383. + const URLPatternSet& url_pattern_set);
  6384. +
  6385. +} // namespace extensions
  6386. +
  6387. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6388. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  6389. new file mode 100755
  6390. --- /dev/null
  6391. +++ b/components/user_scripts/common/user_script.cc
  6392. @@ -0,0 +1,329 @@
  6393. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6394. +// Use of this source code is governed by a BSD-style license that can be
  6395. +// found in the LICENSE file.
  6396. +
  6397. +#include "user_script.h"
  6398. +
  6399. +#include <stddef.h>
  6400. +#include <stdint.h>
  6401. +
  6402. +#include <memory>
  6403. +#include <utility>
  6404. +
  6405. +#include "base/atomic_sequence_num.h"
  6406. +#include "base/command_line.h"
  6407. +#include "base/pickle.h"
  6408. +#include "base/strings/pattern.h"
  6409. +#include "base/strings/string_util.h"
  6410. +#include "user_scripts_features.h"
  6411. +
  6412. +namespace {
  6413. +
  6414. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  6415. +// from multiple threads.
  6416. +base::AtomicSequenceNumber g_user_script_id_generator;
  6417. +
  6418. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  6419. + const GURL& url) {
  6420. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  6421. + if (base::MatchPattern(url.spec(), *glob))
  6422. + return true;
  6423. + }
  6424. +
  6425. + return false;
  6426. +}
  6427. +
  6428. +} // namespace
  6429. +
  6430. +namespace user_scripts {
  6431. +
  6432. +// The bitmask for valid user script injectable schemes used by URLPattern.
  6433. +enum {
  6434. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  6435. + URLPattern::SCHEME_HTTP |
  6436. + URLPattern::SCHEME_HTTPS
  6437. + //| URLPattern::SCHEME_FILE |
  6438. + //URLPattern::SCHEME_FTP
  6439. +};
  6440. +
  6441. +// static
  6442. +const char UserScript::kFileExtension[] = ".user.js";
  6443. +
  6444. +// static
  6445. +int UserScript::GenerateUserScriptID() {
  6446. + return g_user_script_id_generator.GetNext();
  6447. +}
  6448. +
  6449. +bool UserScript::IsURLUserScript(const GURL& url,
  6450. + const std::string& mime_type) {
  6451. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  6452. + base::CompareCase::INSENSITIVE_ASCII) &&
  6453. + mime_type != "text/html";
  6454. +}
  6455. +
  6456. +// static
  6457. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  6458. + if (canExecuteScriptEverywhere)
  6459. + return URLPattern::SCHEME_ALL;
  6460. + int valid_schemes = kValidUserScriptSchemes;
  6461. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  6462. + // switches::kExtensionsOnChromeURLs)) {
  6463. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  6464. + // }
  6465. + return valid_schemes;
  6466. +}
  6467. +
  6468. +UserScript::File::File(const base::FilePath& extension_root,
  6469. + const base::FilePath& relative_path,
  6470. + const GURL& url)
  6471. + : extension_root_(extension_root),
  6472. + relative_path_(relative_path),
  6473. + url_(url) {
  6474. +}
  6475. +
  6476. +UserScript::File::File() {}
  6477. +
  6478. +UserScript::File::File(const File& other)
  6479. + : extension_root_(other.extension_root_),
  6480. + relative_path_(other.relative_path_),
  6481. + url_(other.url_),
  6482. + external_content_(other.external_content_),
  6483. + content_(other.content_),
  6484. + key_(other.key_) {}
  6485. +
  6486. +UserScript::File::~File() {}
  6487. +
  6488. +UserScript::UserScript() = default;
  6489. +UserScript::~UserScript() = default;
  6490. +
  6491. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  6492. + url_set_.AddPattern(pattern);
  6493. +}
  6494. +
  6495. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  6496. + exclude_url_set_.AddPattern(pattern);
  6497. +}
  6498. +
  6499. +bool UserScript::MatchesURL(const GURL& url) const {
  6500. + // Since the injecton is also provided for native pages,
  6501. + // we must verify that the render process does not include
  6502. + // scripts in the schema that are not allowed
  6503. +
  6504. + // we allow only URLPattern::SCHEME_HTTP(S)
  6505. + URLPattern pattern(kValidUserScriptSchemes);
  6506. + pattern.Parse(url.spec());
  6507. + if (!pattern.IsValidScheme(pattern.scheme()))
  6508. + return false;
  6509. +
  6510. + if (!url_set_.is_empty()) {
  6511. + if (!url_set_.MatchesURL(url)) {
  6512. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6513. + LOG(INFO) << "UserScripts: No Match for url_set";
  6514. + return false;
  6515. + }
  6516. + }
  6517. +
  6518. + if (!exclude_url_set_.is_empty()) {
  6519. + if (exclude_url_set_.MatchesURL(url)) {
  6520. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6521. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  6522. + return false;
  6523. + }
  6524. + }
  6525. +
  6526. + if (!globs_.empty()) {
  6527. + if (!UrlMatchesGlobs(&globs_, url)) {
  6528. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6529. + LOG(INFO) << "UserScripts: No Match for globs";
  6530. + return false;
  6531. + }
  6532. + }
  6533. +
  6534. + if (!exclude_globs_.empty()) {
  6535. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  6536. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6537. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  6538. + return false;
  6539. + }
  6540. + }
  6541. +
  6542. + return true;
  6543. +}
  6544. +
  6545. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  6546. + bool is_subframe) const {
  6547. + if (is_subframe && !match_all_frames())
  6548. + return false;
  6549. +
  6550. + return MatchesURL(effective_document_url);
  6551. +}
  6552. +
  6553. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  6554. + pickle->WriteString(url_.spec());
  6555. + // Do not write path. It's not needed in the renderer.
  6556. + // Do not write content. It will be serialized by other means.
  6557. +}
  6558. +
  6559. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  6560. + base::PickleIterator* iter) {
  6561. + // Read the url from the pickle.
  6562. + std::string url;
  6563. + CHECK(iter->ReadString(&url));
  6564. + set_url(GURL(url));
  6565. +}
  6566. +
  6567. +void UserScript::Pickle(base::Pickle* pickle) const {
  6568. + // Write the simple types to the pickle.
  6569. + pickle->WriteInt(run_location());
  6570. + pickle->WriteInt(user_script_id_);
  6571. + pickle->WriteString(name_);
  6572. + pickle->WriteBool(emulate_greasemonkey());
  6573. + pickle->WriteBool(match_all_frames());
  6574. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  6575. + pickle->WriteBool(is_incognito_enabled());
  6576. +
  6577. + PickleHostID(pickle, host_id_);
  6578. + pickle->WriteInt(consumer_instance_type());
  6579. + PickleGlobs(pickle, globs_);
  6580. + PickleGlobs(pickle, exclude_globs_);
  6581. + PickleURLPatternSet(pickle, url_set_);
  6582. + PickleURLPatternSet(pickle, exclude_url_set_);
  6583. + PickleScripts(pickle, js_scripts_);
  6584. + PickleScripts(pickle, css_scripts_);
  6585. +}
  6586. +
  6587. +void UserScript::PickleGlobs(base::Pickle* pickle,
  6588. + const std::vector<std::string>& globs) const {
  6589. + pickle->WriteUInt32(globs.size());
  6590. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  6591. + pickle->WriteString(*glob);
  6592. + }
  6593. +}
  6594. +
  6595. +void UserScript::PickleHostID(base::Pickle* pickle,
  6596. + const HostID& host_id) const {
  6597. + pickle->WriteInt(host_id.type());
  6598. + pickle->WriteString(host_id.id());
  6599. +}
  6600. +
  6601. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  6602. + const URLPatternSet& pattern_list) const {
  6603. + pickle->WriteUInt32(pattern_list.patterns().size());
  6604. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  6605. + ++pattern) {
  6606. + pickle->WriteInt(pattern->valid_schemes());
  6607. + pickle->WriteString(pattern->GetAsString());
  6608. + }
  6609. +}
  6610. +
  6611. +void UserScript::PickleScripts(base::Pickle* pickle,
  6612. + const FileList& scripts) const {
  6613. + pickle->WriteUInt32(scripts.size());
  6614. + for (const std::unique_ptr<File>& file : scripts)
  6615. + file->Pickle(pickle);
  6616. +}
  6617. +
  6618. +void UserScript::Unpickle(const base::Pickle& pickle,
  6619. + base::PickleIterator* iter) {
  6620. + // Read the run location.
  6621. + int run_location = 0;
  6622. + CHECK(iter->ReadInt(&run_location));
  6623. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  6624. + run_location_ = static_cast<RunLocation>(run_location);
  6625. +
  6626. + CHECK(iter->ReadInt(&user_script_id_));
  6627. + CHECK(iter->ReadString(&name_));
  6628. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  6629. + CHECK(iter->ReadBool(&match_all_frames_));
  6630. + int match_origin_as_fallback_int = 0;
  6631. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  6632. + match_origin_as_fallback_ =
  6633. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  6634. + CHECK(iter->ReadBool(&incognito_enabled_));
  6635. +
  6636. + UnpickleHostID(pickle, iter, &host_id_);
  6637. +
  6638. + int consumer_instance_type = 0;
  6639. + CHECK(iter->ReadInt(&consumer_instance_type));
  6640. + consumer_instance_type_ =
  6641. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  6642. +
  6643. + UnpickleGlobs(pickle, iter, &globs_);
  6644. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  6645. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  6646. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  6647. + UnpickleScripts(pickle, iter, &js_scripts_);
  6648. + UnpickleScripts(pickle, iter, &css_scripts_);
  6649. +}
  6650. +
  6651. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  6652. + base::PickleIterator* iter,
  6653. + std::vector<std::string>* globs) {
  6654. + uint32_t num_globs = 0;
  6655. + CHECK(iter->ReadUInt32(&num_globs));
  6656. + globs->clear();
  6657. + for (uint32_t i = 0; i < num_globs; ++i) {
  6658. + std::string glob;
  6659. + CHECK(iter->ReadString(&glob));
  6660. + globs->push_back(glob);
  6661. + }
  6662. +}
  6663. +
  6664. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  6665. + base::PickleIterator* iter,
  6666. + HostID* host_id) {
  6667. + int type = 0;
  6668. + std::string id;
  6669. + CHECK(iter->ReadInt(&type));
  6670. + CHECK(iter->ReadString(&id));
  6671. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  6672. +}
  6673. +
  6674. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  6675. + base::PickleIterator* iter,
  6676. + URLPatternSet* pattern_list) {
  6677. + uint32_t num_patterns = 0;
  6678. + CHECK(iter->ReadUInt32(&num_patterns));
  6679. +
  6680. + pattern_list->ClearPatterns();
  6681. + for (uint32_t i = 0; i < num_patterns; ++i) {
  6682. + int valid_schemes;
  6683. + CHECK(iter->ReadInt(&valid_schemes));
  6684. +
  6685. + std::string pattern_str;
  6686. + CHECK(iter->ReadString(&pattern_str));
  6687. +
  6688. + URLPattern pattern(kValidUserScriptSchemes);
  6689. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  6690. + CHECK(URLPattern::ParseResult::kSuccess == result)
  6691. + << URLPattern::GetParseResultString(result) << " "
  6692. + << pattern_str.c_str();
  6693. +
  6694. + pattern.SetValidSchemes(valid_schemes);
  6695. + pattern_list->AddPattern(pattern);
  6696. + }
  6697. +}
  6698. +
  6699. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  6700. + base::PickleIterator* iter,
  6701. + FileList* scripts) {
  6702. + uint32_t num_files = 0;
  6703. + CHECK(iter->ReadUInt32(&num_files));
  6704. + scripts->clear();
  6705. + for (uint32_t i = 0; i < num_files; ++i) {
  6706. + std::unique_ptr<File> file(new File());
  6707. + file->Unpickle(pickle, iter);
  6708. + scripts->push_back(std::move(file));
  6709. + }
  6710. +}
  6711. +
  6712. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  6713. + : id(id), host_id(host_id) {}
  6714. +
  6715. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  6716. +
  6717. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  6718. + return a.id < b.id;
  6719. +}
  6720. +
  6721. +} // namespace extensions
  6722. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  6723. new file mode 100755
  6724. --- /dev/null
  6725. +++ b/components/user_scripts/common/user_script.h
  6726. @@ -0,0 +1,403 @@
  6727. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6728. +// Use of this source code is governed by a BSD-style license that can be
  6729. +// found in the LICENSE file.
  6730. +
  6731. +#ifndef USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6732. +#define USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6733. +
  6734. +#include <memory>
  6735. +#include <string>
  6736. +#include <vector>
  6737. +
  6738. +#include "base/files/file_path.h"
  6739. +#include "base/strings/string_piece.h"
  6740. +#include "script_constants.h"
  6741. +#include "host_id.h"
  6742. +#include "url_pattern.h"
  6743. +#include "url_pattern_set.h"
  6744. +#include "url/gurl.h"
  6745. +
  6746. +namespace base {
  6747. +class Pickle;
  6748. +class PickleIterator;
  6749. +}
  6750. +
  6751. +namespace user_scripts {
  6752. +
  6753. +// Represents a user script, either a standalone one, or one that is part of an
  6754. +// extension.
  6755. +class UserScript {
  6756. + public:
  6757. + UserScript(const UserScript&) = delete;
  6758. + UserScript& operator=(const UserScript&) = delete;
  6759. + // The file extension for standalone user scripts.
  6760. + static const char kFileExtension[];
  6761. +
  6762. + static int GenerateUserScriptID();
  6763. +
  6764. + // Check if a URL should be treated as a user script and converted to an
  6765. + // extension.
  6766. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  6767. +
  6768. + // Get the valid user script schemes for the current process. If
  6769. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6770. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6771. +
  6772. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6773. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6774. + // The type of injected script.
  6775. + enum InjectionType {
  6776. + // A content script specified in the extension's manifest.
  6777. + CONTENT_SCRIPT,
  6778. + // A script injected via, e.g. tabs.executeScript().
  6779. + //PROGRAMMATIC_SCRIPT
  6780. + };
  6781. + // The last type of injected script; used for enum verification in IPC.
  6782. + // Update this if you add more injected script types!
  6783. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6784. +
  6785. + // Locations that user scripts can be run inside the document.
  6786. + // The three run locations must strictly follow each other in both load order
  6787. + // (i.e., start *always* comes before end) and numerically, as we use
  6788. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6789. + enum RunLocation {
  6790. + UNDEFINED,
  6791. + DOCUMENT_START, // After the documentElement is created, but before
  6792. + // anything else happens.
  6793. + DOCUMENT_END, // After the entire document is parsed. Same as
  6794. + // DOMContentLoaded.
  6795. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6796. + // is "idle". Currently this uses the simple heuristic of:
  6797. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6798. + // particular injection point is guaranteed.
  6799. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6800. + // reasons, and was executed at a later time.
  6801. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6802. + // IPC in the browser process.
  6803. + RUN_LOCATION_LAST // Leave this as the last item.
  6804. + };
  6805. +
  6806. + // Holds script file info.
  6807. + class File {
  6808. + public:
  6809. + File(const base::FilePath& extension_root,
  6810. + const base::FilePath& relative_path,
  6811. + const GURL& url);
  6812. + File();
  6813. + File(const File& other);
  6814. + ~File();
  6815. +
  6816. + const base::FilePath& extension_root() const { return extension_root_; }
  6817. + const base::FilePath& relative_path() const { return relative_path_; }
  6818. +
  6819. + const GURL& url() const { return url_; }
  6820. + void set_url(const GURL& url) { url_ = url; }
  6821. +
  6822. + // If external_content_ is set returns it as content otherwise it returns
  6823. + // content_
  6824. + const base::StringPiece GetContent() const {
  6825. + if (external_content_.data())
  6826. + return external_content_;
  6827. + else
  6828. + return content_;
  6829. + }
  6830. + void set_external_content(const base::StringPiece& content) {
  6831. + external_content_ = content;
  6832. + }
  6833. + void set_content(const base::StringPiece& content) {
  6834. + content_.assign(content.begin(), content.end());
  6835. + }
  6836. +
  6837. + const std::string& key() const { return key_; }
  6838. + void set_key(const std::string& key) {
  6839. + key_ = key;
  6840. + }
  6841. +
  6842. + // Serialization support. The content and FilePath members will not be
  6843. + // serialized!
  6844. + void Pickle(base::Pickle* pickle) const;
  6845. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6846. +
  6847. + private:
  6848. + // Where the script file lives on the disk. We keep the path split so that
  6849. + // it can be localized at will.
  6850. + base::FilePath extension_root_;
  6851. + base::FilePath relative_path_;
  6852. +
  6853. + // The url to this script file.
  6854. + GURL url_;
  6855. +
  6856. + // The script content. It can be set to either loaded_content_ or
  6857. + // externally allocated string.
  6858. + base::StringPiece external_content_;
  6859. +
  6860. + // Set when the content is loaded by LoadContent
  6861. + std::string content_;
  6862. +
  6863. + std::string key_;
  6864. + };
  6865. +
  6866. + using FileList = std::vector<std::unique_ptr<File>>;
  6867. +
  6868. + // Type of a API consumer instance that user scripts will be injected on.
  6869. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6870. +
  6871. + // Constructor. Default the run location to document end, which is like
  6872. + // Greasemonkey and probably more useful for typical scripts.
  6873. + UserScript();
  6874. + ~UserScript();
  6875. +
  6876. + // Performs a copy of all fields except file contents.
  6877. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6878. +
  6879. + const std::string& name_space() const { return name_space_; }
  6880. + void set_name_space(const std::string& name_space) {
  6881. + name_space_ = name_space;
  6882. + }
  6883. +
  6884. + const std::string& name() const { return name_; }
  6885. + void set_name(const std::string& name) { name_ = name; }
  6886. +
  6887. + const std::string& version() const { return version_; }
  6888. + void set_version(const std::string& version) {
  6889. + version_ = version;
  6890. + }
  6891. +
  6892. + const std::string& key() const { return key_; }
  6893. + void set_key(const std::string& key) {
  6894. + key_ = key;
  6895. + }
  6896. +
  6897. + const std::string& file_path() const { return file_path_; }
  6898. + void set_file_path(const std::string& file_path) {
  6899. + file_path_ = file_path;
  6900. + }
  6901. +
  6902. + const std::string& url_source() const { return url_source_; }
  6903. + void set_url_source(const std::string& url_source) {
  6904. + url_source_ = url_source;
  6905. + }
  6906. +
  6907. + const std::string& description() const { return description_; }
  6908. + void set_description(const std::string& description) {
  6909. + description_ = description;
  6910. + }
  6911. +
  6912. + const std::string& parser_error() const { return parser_error_; }
  6913. + void set_parser_error(const std::string& parser_error) {
  6914. + parser_error_ = parser_error;
  6915. + }
  6916. +
  6917. + bool force_disabled() const { return force_disabled_; }
  6918. + void set_force_disabled() {
  6919. + force_disabled_ = true;
  6920. + }
  6921. +
  6922. + // The place in the document to run the script.
  6923. + RunLocation run_location() const { return run_location_; }
  6924. + void set_run_location(RunLocation location) { run_location_ = location; }
  6925. +
  6926. + // Whether to emulate greasemonkey when running this script.
  6927. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6928. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6929. +
  6930. + // Whether to match all frames, or only the top one.
  6931. + bool match_all_frames() const { return match_all_frames_; }
  6932. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6933. +
  6934. + // Whether to match the origin as a fallback if the URL cannot be used
  6935. + // directly.
  6936. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6937. + return match_origin_as_fallback_;
  6938. + }
  6939. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6940. + match_origin_as_fallback_ = val;
  6941. + }
  6942. +
  6943. + // The globs, if any, that determine which pages this script runs against.
  6944. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6945. + const std::vector<std::string>& globs() const { return globs_; }
  6946. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6947. + void clear_globs() { globs_.clear(); }
  6948. + const std::vector<std::string>& exclude_globs() const {
  6949. + return exclude_globs_;
  6950. + }
  6951. + void add_exclude_glob(const std::string& glob) {
  6952. + exclude_globs_.push_back(glob);
  6953. + }
  6954. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6955. +
  6956. + // The URLPatterns, if any, that determine which pages this script runs
  6957. + // against.
  6958. + const URLPatternSet& url_patterns() const { return url_set_; }
  6959. + void add_url_pattern(const URLPattern& pattern);
  6960. + const URLPatternSet& exclude_url_patterns() const {
  6961. + return exclude_url_set_;
  6962. + }
  6963. + void add_exclude_url_pattern(const URLPattern& pattern);
  6964. +
  6965. + // List of js scripts for this user script
  6966. + FileList& js_scripts() { return js_scripts_; }
  6967. + const FileList& js_scripts() const { return js_scripts_; }
  6968. +
  6969. + // List of css scripts for this user script
  6970. + FileList& css_scripts() { return css_scripts_; }
  6971. + const FileList& css_scripts() const { return css_scripts_; }
  6972. +
  6973. + const std::string& extension_id() const { return host_id_.id(); }
  6974. +
  6975. + const HostID& host_id() const { return host_id_; }
  6976. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  6977. +
  6978. + const ConsumerInstanceType& consumer_instance_type() const {
  6979. + return consumer_instance_type_;
  6980. + }
  6981. + void set_consumer_instance_type(
  6982. + const ConsumerInstanceType& consumer_instance_type) {
  6983. + consumer_instance_type_ = consumer_instance_type;
  6984. + }
  6985. +
  6986. + int id() const { return user_script_id_; }
  6987. + void set_id(int id) { user_script_id_ = id; }
  6988. +
  6989. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  6990. + // belong here. We should be able to determine this in the renderer/ where it
  6991. + // is used.
  6992. + bool is_incognito_enabled() const { return incognito_enabled_; }
  6993. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  6994. +
  6995. + // Returns true if the script should be applied to the specified URL, false
  6996. + // otherwise.
  6997. + bool MatchesURL(const GURL& url) const;
  6998. +
  6999. + // Returns true if the script should be applied to the given
  7000. + // |effective_document_url|. It is the caller's responsibility to calculate
  7001. + // |effective_document_url| based on match_origin_as_fallback().
  7002. + bool MatchesDocument(const GURL& effective_document_url,
  7003. + bool is_subframe) const;
  7004. +
  7005. + // Serializes the UserScript into a pickle. The content of the scripts and
  7006. + // paths to UserScript::Files will not be serialized!
  7007. + void Pickle(base::Pickle* pickle) const;
  7008. +
  7009. + // Deserializes the script from a pickle. Note that this always succeeds
  7010. + // because presumably we were the one that pickled it, and we did it
  7011. + // correctly.
  7012. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  7013. +
  7014. + private:
  7015. + // base::Pickle helper functions used to pickle the individual types of
  7016. + // components.
  7017. + void PickleGlobs(base::Pickle* pickle,
  7018. + const std::vector<std::string>& globs) const;
  7019. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  7020. + void PickleURLPatternSet(base::Pickle* pickle,
  7021. + const URLPatternSet& pattern_list) const;
  7022. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  7023. +
  7024. + // Unpickle helper functions used to unpickle individual types of components.
  7025. + void UnpickleGlobs(const base::Pickle& pickle,
  7026. + base::PickleIterator* iter,
  7027. + std::vector<std::string>* globs);
  7028. + void UnpickleHostID(const base::Pickle& pickle,
  7029. + base::PickleIterator* iter,
  7030. + HostID* host_id);
  7031. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  7032. + base::PickleIterator* iter,
  7033. + URLPatternSet* pattern_list);
  7034. + void UnpickleScripts(const base::Pickle& pickle,
  7035. + base::PickleIterator* iter,
  7036. + FileList* scripts);
  7037. +
  7038. + // The location to run the script inside the document.
  7039. + RunLocation run_location_ = DOCUMENT_IDLE;
  7040. +
  7041. + // The namespace of the script. This is used by Greasemonkey in the same way
  7042. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  7043. + std::string name_space_;
  7044. +
  7045. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  7046. + std::string name_;
  7047. +
  7048. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  7049. + std::string description_;
  7050. +
  7051. + // Parser error to show to user
  7052. + std::string parser_error_;
  7053. +
  7054. + // A version number of the script. Only used when parsing Greasemonkey-style
  7055. + // scripts.
  7056. + std::string version_;
  7057. +
  7058. + // Greasemonkey-style globs that determine pages to inject the script into.
  7059. + // These are only used with standalone scripts.
  7060. + std::vector<std::string> globs_;
  7061. + std::vector<std::string> exclude_globs_;
  7062. +
  7063. + // URLPatterns that determine pages to inject the script into. These are
  7064. + // only used with scripts that are part of extensions.
  7065. + URLPatternSet url_set_;
  7066. + URLPatternSet exclude_url_set_;
  7067. +
  7068. + // List of js scripts defined in content_scripts
  7069. + FileList js_scripts_;
  7070. +
  7071. + // List of css scripts defined in content_scripts
  7072. + FileList css_scripts_;
  7073. +
  7074. + // internal key of scripts
  7075. + std::string key_;
  7076. +
  7077. + std::string file_path_;
  7078. +
  7079. + // url source of script
  7080. + std::string url_source_;
  7081. +
  7082. + // The ID of the host this script is a part of. The |ID| of the
  7083. + // |host_id| can be empty if the script is a "standlone" user script.
  7084. + HostID host_id_;
  7085. +
  7086. + // The type of the consumer instance that the script will be injected.
  7087. + ConsumerInstanceType consumer_instance_type_ = TAB;
  7088. +
  7089. + // The globally-unique id associated with this user script. -1 indicates
  7090. + // "invalid".
  7091. + int user_script_id_ = -1;
  7092. +
  7093. + // Whether we should try to emulate Greasemonkey's APIs when running this
  7094. + // script.
  7095. + bool emulate_greasemonkey_ = false;
  7096. +
  7097. + // Whether the user script should run in all frames, or only just the top one.
  7098. + bool match_all_frames_ = false;
  7099. +
  7100. + // Whether the user script should run in frames whose initiator / precursor
  7101. + // origin matches a match pattern, if an appropriate URL cannot be found for
  7102. + // the frame for matching purposes, such as in the case of about:, data:, and
  7103. + // other schemes.
  7104. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  7105. + MatchOriginAsFallbackBehavior::kNever;
  7106. +
  7107. + // True if the script should be injected into an incognito tab.
  7108. + bool incognito_enabled_ = false;
  7109. +
  7110. + // Script cannot be enabled
  7111. + bool force_disabled_ = false;
  7112. +};
  7113. +
  7114. +// Information we need while removing scripts from a UserScriptLoader.
  7115. +struct UserScriptIDPair {
  7116. + UserScriptIDPair(int id, const HostID& host_id);
  7117. + explicit UserScriptIDPair(int id);
  7118. +
  7119. + int id;
  7120. + HostID host_id;
  7121. +};
  7122. +
  7123. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  7124. +
  7125. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  7126. +
  7127. +} // namespace extensions
  7128. +
  7129. +#endif // USERSCRIPTS_COMMON_USER_SCRIPT_H_
  7130. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  7131. new file mode 100644
  7132. --- /dev/null
  7133. +++ b/components/user_scripts/common/user_scripts_features.cc
  7134. @@ -0,0 +1,32 @@
  7135. +/*
  7136. + This file is part of Bromite.
  7137. +
  7138. + Bromite is free software: you can redistribute it and/or modify
  7139. + it under the terms of the GNU General Public License as published by
  7140. + the Free Software Foundation, either version 3 of the License, or
  7141. + (at your option) any later version.
  7142. +
  7143. + Bromite is distributed in the hope that it will be useful,
  7144. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7145. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7146. + GNU General Public License for more details.
  7147. +
  7148. + You should have received a copy of the GNU General Public License
  7149. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7150. +*/
  7151. +
  7152. +#include "user_scripts_features.h"
  7153. +
  7154. +#include "build/build_config.h"
  7155. +
  7156. +namespace user_scripts {
  7157. +
  7158. +namespace features {
  7159. +
  7160. +const base::Feature kEnableLoggingUserScripts =
  7161. + {"EnableLoggingUserScripts",
  7162. + base::FEATURE_DISABLED_BY_DEFAULT};
  7163. +
  7164. +}
  7165. +
  7166. +}
  7167. \ No newline at end of file
  7168. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  7169. new file mode 100644
  7170. --- /dev/null
  7171. +++ b/components/user_scripts/common/user_scripts_features.h
  7172. @@ -0,0 +1,34 @@
  7173. +/*
  7174. + This file is part of Bromite.
  7175. +
  7176. + Bromite is free software: you can redistribute it and/or modify
  7177. + it under the terms of the GNU General Public License as published by
  7178. + the Free Software Foundation, either version 3 of the License, or
  7179. + (at your option) any later version.
  7180. +
  7181. + Bromite is distributed in the hope that it will be useful,
  7182. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7183. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7184. + GNU General Public License for more details.
  7185. +
  7186. + You should have received a copy of the GNU General Public License
  7187. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7188. +*/
  7189. +
  7190. +#ifndef USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7191. +#define USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7192. +
  7193. +// This file defines all the base::FeatureList features for the Password Manager
  7194. +// module.
  7195. +
  7196. +#include "base/feature_list.h"
  7197. +
  7198. +namespace user_scripts {
  7199. +
  7200. +namespace features {
  7201. + extern const base::Feature kEnableLoggingUserScripts;
  7202. +}
  7203. +
  7204. +}
  7205. +
  7206. +#endif
  7207. \ No newline at end of file
  7208. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  7209. new file mode 100755
  7210. --- /dev/null
  7211. +++ b/components/user_scripts/common/view_type.cc
  7212. @@ -0,0 +1,39 @@
  7213. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7214. +// Use of this source code is governed by a BSD-style license that can be
  7215. +// found in the LICENSE file.
  7216. +
  7217. +#include "view_type.h"
  7218. +
  7219. +#include "base/strings/string_piece.h"
  7220. +
  7221. +namespace user_scripts {
  7222. +
  7223. +bool GetViewTypeFromString(const std::string& view_type,
  7224. + ViewType* view_type_out) {
  7225. + // TODO(devlin): This map doesn't contain the following values:
  7226. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  7227. + // - VIEW_TYPE_COMPONENT
  7228. + // - VIEW_TYPE_EXTENSION_GUEST
  7229. + // Why? Is it just because we don't expose those types to JS?
  7230. + static const struct {
  7231. + ViewType type;
  7232. + base::StringPiece name;
  7233. + } constexpr kTypeMap[] = {
  7234. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  7235. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  7236. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  7237. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  7238. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  7239. + };
  7240. +
  7241. + for (const auto& entry : kTypeMap) {
  7242. + if (entry.name == view_type) {
  7243. + *view_type_out = entry.type;
  7244. + return true;
  7245. + }
  7246. + }
  7247. +
  7248. + return false;
  7249. +}
  7250. +
  7251. +} // namespace extensions
  7252. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  7253. new file mode 100755
  7254. --- /dev/null
  7255. +++ b/components/user_scripts/common/view_type.h
  7256. @@ -0,0 +1,48 @@
  7257. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7258. +// Use of this source code is governed by a BSD-style license that can be
  7259. +// found in the LICENSE file.
  7260. +
  7261. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7262. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7263. +
  7264. +#include <string>
  7265. +
  7266. +namespace user_scripts {
  7267. +
  7268. +// Icky RTTI used by a few systems to distinguish the host type of a given
  7269. +// WebContents.
  7270. +//
  7271. +// Do not change or reuse the the entry values in this list as this is used in
  7272. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  7273. +//
  7274. +// TODO(aa): Remove this and teach those systems to keep track of their own
  7275. +// data.
  7276. +enum ViewType {
  7277. + VIEW_TYPE_INVALID = 0,
  7278. + // VIEW_TYPE_APP_WINDOW = 1,
  7279. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  7280. +
  7281. + // // For custom parts of Chrome if no other type applies.
  7282. + // VIEW_TYPE_COMPONENT = 3,
  7283. +
  7284. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  7285. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  7286. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  7287. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  7288. +
  7289. + // Panels were removed in https://crbug.com/571511.
  7290. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  7291. +
  7292. + VIEW_TYPE_TAB_CONTENTS = 9,
  7293. +
  7294. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  7295. +};
  7296. +
  7297. +// Matches the |view_type| to the corresponding ViewType, and populates
  7298. +// |view_type_out|. Returns true if a match is found.
  7299. +bool GetViewTypeFromString(const std::string& view_type,
  7300. + ViewType* view_type_out);
  7301. +
  7302. +} // namespace extensions
  7303. +
  7304. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7305. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  7306. new file mode 100755
  7307. --- /dev/null
  7308. +++ b/components/user_scripts/renderer/BUILD.gn
  7309. @@ -0,0 +1,67 @@
  7310. +# Copyright 2015 The Chromium Authors. All rights reserved.
  7311. +# Use of this source code is governed by a BSD-style license that can be
  7312. +# found in the LICENSE file.
  7313. +
  7314. +import("//tools/grit/grit_rule.gni")
  7315. +import("//tools/grit/repack.gni")
  7316. +
  7317. +group("user_scripts_resources") {
  7318. + public_deps = [
  7319. + ":user_scripts_renderer_resources",
  7320. + ]
  7321. +}
  7322. +
  7323. +grit("user_scripts_renderer_resources") {
  7324. + source = "resources/user_scripts_renderer_resources.grd"
  7325. + outputs = [
  7326. + "grit/user_scripts_renderer_resources.h",
  7327. + "user_scripts_renderer_resources.pak",
  7328. + ]
  7329. + grit_flags = [
  7330. + "-E",
  7331. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  7332. + ]
  7333. +}
  7334. +
  7335. +static_library("renderer") {
  7336. + sources = [
  7337. + "extension_frame_helper.cc",
  7338. + "extension_frame_helper.h",
  7339. + "injection_host.cc",
  7340. + "injection_host.h",
  7341. + "script_injection_manager.cc",
  7342. + "script_injection_manager.h",
  7343. + "script_injection_callback.cc",
  7344. + "script_injection_callback.h",
  7345. + "script_injection.cc",
  7346. + "script_injection.h",
  7347. + "script_injector.h",
  7348. + "script_context.cc",
  7349. + "script_context.h",
  7350. + "scripts_run_info.cc",
  7351. + "scripts_run_info.h",
  7352. + "user_script_injector.cc",
  7353. + "user_script_injector.h",
  7354. + "user_script_set_manager.cc",
  7355. + "user_script_set_manager.h",
  7356. + "user_script_set.cc",
  7357. + "user_script_set.h",
  7358. + "user_scripts_dispatcher.cc",
  7359. + "user_scripts_dispatcher.h",
  7360. + "user_scripts_renderer_client.cc",
  7361. + "user_scripts_renderer_client.h",
  7362. + "web_ui_injection_host.cc",
  7363. + "web_ui_injection_host.h",
  7364. + ]
  7365. +
  7366. + deps = [
  7367. + ":user_scripts_resources",
  7368. + "//base",
  7369. + "//content/public/common",
  7370. + "//content/public/renderer",
  7371. + "//components/user_scripts/common",
  7372. + "//mojo/public/cpp/bindings",
  7373. + "//third_party/blink/public:blink_headers",
  7374. + "//v8",
  7375. + ]
  7376. +}
  7377. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  7378. new file mode 100755
  7379. --- /dev/null
  7380. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  7381. @@ -0,0 +1,96 @@
  7382. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7383. +// Use of this source code is governed by a BSD-style license that can be
  7384. +// found in the LICENSE file.
  7385. +
  7386. +#include "extension_frame_helper.h"
  7387. +
  7388. +#include <set>
  7389. +
  7390. +#include "base/metrics/histogram_macros.h"
  7391. +#include "base/strings/string_util.h"
  7392. +#include "base/timer/elapsed_timer.h"
  7393. +#include "content/public/renderer/render_frame.h"
  7394. +#include "content/public/renderer/render_view.h"
  7395. +#include "../common/constants.h"
  7396. +#include "third_party/blink/public/platform/web_security_origin.h"
  7397. +#include "third_party/blink/public/web/web_console_message.h"
  7398. +#include "third_party/blink/public/web/web_document.h"
  7399. +#include "third_party/blink/public/web/web_document_loader.h"
  7400. +#include "third_party/blink/public/web/web_local_frame.h"
  7401. +#include "third_party/blink/public/web/web_settings.h"
  7402. +#include "third_party/blink/public/web/web_view.h"
  7403. +
  7404. +namespace user_scripts {
  7405. +
  7406. +namespace {
  7407. +
  7408. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  7409. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  7410. +
  7411. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  7412. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  7413. +void RunCallbacksWhileFrameIsValid(
  7414. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  7415. + std::vector<base::OnceClosure>* callbacks_to_be_run_and_cleared) {
  7416. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  7417. + // callbacks that are added during the iteration.
  7418. + std::vector<base::OnceClosure> callbacks;
  7419. + callbacks_to_be_run_and_cleared->swap(callbacks);
  7420. + for (auto& callback : callbacks) {
  7421. + std::move(callback).Run();
  7422. + if (!frame_helper.get())
  7423. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  7424. + }
  7425. +}
  7426. +
  7427. +} // namespace
  7428. +
  7429. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  7430. + : content::RenderFrameObserver(render_frame),
  7431. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  7432. + tab_id_(-1) {
  7433. + g_frame_helpers.Get().insert(this);
  7434. +}
  7435. +
  7436. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  7437. + g_frame_helpers.Get().erase(this);
  7438. +}
  7439. +
  7440. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  7441. + base::OnceClosure callback) {
  7442. + document_element_created_callbacks_.push_back(std::move(callback));
  7443. +}
  7444. +
  7445. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  7446. + base::OnceClosure callback) {
  7447. + document_load_finished_callbacks_.push_back(std::move(callback));
  7448. +}
  7449. +
  7450. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  7451. + base::OnceClosure callback) {
  7452. + document_idle_callbacks_.push_back(std::move(callback));
  7453. +}
  7454. +
  7455. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  7456. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7457. + &document_element_created_callbacks_);
  7458. + // |this| might be dead by now.
  7459. +}
  7460. +
  7461. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  7462. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7463. + &document_load_finished_callbacks_);
  7464. + // |this| might be dead by now.
  7465. +}
  7466. +
  7467. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  7468. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7469. + &document_idle_callbacks_);
  7470. + // |this| might be dead by now.
  7471. +}
  7472. +
  7473. +void ExtensionFrameHelper::OnDestruct() {
  7474. + delete this;
  7475. +}
  7476. +
  7477. +} // namespace user_scripts
  7478. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  7479. new file mode 100755
  7480. --- /dev/null
  7481. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  7482. @@ -0,0 +1,91 @@
  7483. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7484. +// Use of this source code is governed by a BSD-style license that can be
  7485. +// found in the LICENSE file.
  7486. +
  7487. +#ifndef USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7488. +#define USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7489. +
  7490. +#include <string>
  7491. +#include <vector>
  7492. +
  7493. +#include "base/callback_forward.h"
  7494. +#include "base/memory/weak_ptr.h"
  7495. +#include "content/public/renderer/render_frame_observer.h"
  7496. +#include "content/public/renderer/render_frame_observer_tracker.h"
  7497. +#include "../common/view_type.h"
  7498. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  7499. +#include "v8/include/v8.h"
  7500. +
  7501. +struct ExtensionMsg_ExternalConnectionInfo;
  7502. +struct ExtensionMsg_TabConnectionInfo;
  7503. +
  7504. +namespace base {
  7505. +class ListValue;
  7506. +}
  7507. +
  7508. +namespace user_scripts {
  7509. +
  7510. +class Dispatcher;
  7511. +struct Message;
  7512. +struct PortId;
  7513. +class ScriptContext;
  7514. +
  7515. +// RenderFrame-level plumbing for extension features.
  7516. +class ExtensionFrameHelper
  7517. + : public content::RenderFrameObserver,
  7518. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  7519. + public:
  7520. + ExtensionFrameHelper(const ExtensionFrameHelper&) = delete;
  7521. + ExtensionFrameHelper& operator=(const ExtensionFrameHelper&) = delete;
  7522. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  7523. + Dispatcher* extension_dispatcher*/);
  7524. + ~ExtensionFrameHelper() override;
  7525. +
  7526. + int tab_id() const { return tab_id_; }
  7527. +
  7528. + // Called when the document element has been inserted in this frame. This
  7529. + // method may invoke untrusted JavaScript code that invalidate the frame and
  7530. + // this ExtensionFrameHelper.
  7531. + void RunScriptsAtDocumentStart();
  7532. +
  7533. + // Called after the DOMContentLoaded event has fired.
  7534. + void RunScriptsAtDocumentEnd();
  7535. +
  7536. + // Called before the window.onload event is fired.
  7537. + void RunScriptsAtDocumentIdle();
  7538. +
  7539. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  7540. + // notification. Only call this when you are certain that there will be such a
  7541. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  7542. + // Otherwise the callback is never invoked, or invoked for a document that you
  7543. + // were not expecting.
  7544. + void ScheduleAtDocumentStart(base::OnceClosure callback);
  7545. +
  7546. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  7547. + void ScheduleAtDocumentEnd(base::OnceClosure callback);
  7548. +
  7549. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  7550. + void ScheduleAtDocumentIdle(base::OnceClosure callback);
  7551. +
  7552. + private:
  7553. +
  7554. + void OnDestruct() override;
  7555. +
  7556. + // The id of the tab the render frame is attached to.
  7557. + int tab_id_;
  7558. +
  7559. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  7560. + std::vector<base::OnceClosure> document_element_created_callbacks_;
  7561. +
  7562. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  7563. + std::vector<base::OnceClosure> document_load_finished_callbacks_;
  7564. +
  7565. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  7566. + std::vector<base::OnceClosure> document_idle_callbacks_;
  7567. +
  7568. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  7569. +};
  7570. +
  7571. +} // namespace extensions
  7572. +
  7573. +#endif // USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7574. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  7575. new file mode 100755
  7576. --- /dev/null
  7577. +++ b/components/user_scripts/renderer/injection_host.cc
  7578. @@ -0,0 +1,12 @@
  7579. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7580. +// Use of this source code is governed by a BSD-style license that can be
  7581. +// found in the LICENSE file.
  7582. +
  7583. +#include "injection_host.h"
  7584. +
  7585. +InjectionHost::InjectionHost(const HostID& host_id) :
  7586. + id_(host_id) {
  7587. +}
  7588. +
  7589. +InjectionHost::~InjectionHost() {
  7590. +}
  7591. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  7592. new file mode 100755
  7593. --- /dev/null
  7594. +++ b/components/user_scripts/renderer/injection_host.h
  7595. @@ -0,0 +1,41 @@
  7596. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7597. +// Use of this source code is governed by a BSD-style license that can be
  7598. +// found in the LICENSE file.
  7599. +
  7600. +#ifndef USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7601. +#define USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7602. +
  7603. +#include "../common/host_id.h"
  7604. +#include "url/gurl.h"
  7605. +
  7606. +namespace content {
  7607. +class RenderFrame;
  7608. +}
  7609. +
  7610. +// An interface for all kinds of hosts who own user scripts.
  7611. +class InjectionHost {
  7612. + public:
  7613. + InjectionHost(const InjectionHost&) = delete;
  7614. + InjectionHost& operator=(const InjectionHost&) = delete;
  7615. + InjectionHost(const HostID& host_id);
  7616. + virtual ~InjectionHost();
  7617. +
  7618. + // Returns the CSP to be used for the isolated world. Currently this only
  7619. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  7620. + // bypassed.
  7621. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  7622. +
  7623. + // The base url for the host.
  7624. + virtual const GURL& url() const = 0;
  7625. +
  7626. + // The human-readable name of the host.
  7627. + virtual const std::string& name() const = 0;
  7628. +
  7629. + const HostID& id() const { return id_; }
  7630. +
  7631. + private:
  7632. + // The ID of the host.
  7633. + HostID id_;
  7634. +};
  7635. +
  7636. +#endif // USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7637. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7638. new file mode 100755
  7639. --- /dev/null
  7640. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7641. @@ -0,0 +1,82 @@
  7642. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7643. +// Use of this source code is governed by a BSD-style license that can be
  7644. +// found in the LICENSE file.
  7645. +
  7646. +// -----------------------------------------------------------------------------
  7647. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  7648. +// have your change take effect.
  7649. +// -----------------------------------------------------------------------------
  7650. +
  7651. +// Partial implementation of the Greasemonkey API, see:
  7652. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  7653. +
  7654. +function GM_addStyle(css) {
  7655. + var parent = document.getElementsByTagName("head")[0];
  7656. + if (!parent) {
  7657. + parent = document.documentElement;
  7658. + }
  7659. + var style = document.createElement("style");
  7660. + style.type = "text/css";
  7661. + var textNode = document.createTextNode(css);
  7662. + style.appendChild(textNode);
  7663. + parent.appendChild(style);
  7664. +}
  7665. +
  7666. +function GM_xmlhttpRequest(details) {
  7667. + function setupEvent(xhr, url, eventName, callback) {
  7668. + xhr[eventName] = function () {
  7669. + var isComplete = xhr.readyState == 4;
  7670. + var responseState = {
  7671. + responseText: xhr.responseText,
  7672. + readyState: xhr.readyState,
  7673. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  7674. + status: isComplete ? xhr.status : 0,
  7675. + statusText: isComplete ? xhr.statusText : "",
  7676. + finalUrl: isComplete ? url : ""
  7677. + };
  7678. + callback(responseState);
  7679. + };
  7680. + }
  7681. +
  7682. + var xhr = new XMLHttpRequest();
  7683. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  7684. + for (var i = 0; i < eventNames.length; i++ ) {
  7685. + var eventName = eventNames[i];
  7686. + if (eventName in details) {
  7687. + setupEvent(xhr, details.url, eventName, details[eventName]);
  7688. + }
  7689. + }
  7690. +
  7691. + xhr.open(details.method, details.url);
  7692. +
  7693. + if (details.overrideMimeType) {
  7694. + xhr.overrideMimeType(details.overrideMimeType);
  7695. + }
  7696. + if (details.headers) {
  7697. + for (var header in details.headers) {
  7698. + xhr.setRequestHeader(header, details.headers[header]);
  7699. + }
  7700. + }
  7701. + xhr.send(details.data ? details.data : null);
  7702. +}
  7703. +
  7704. +function GM_openInTab(url) {
  7705. + window.open(url, "");
  7706. +}
  7707. +
  7708. +function GM_log(message) {
  7709. + window.console.log(message);
  7710. +}
  7711. +
  7712. +(function() {
  7713. + function generateGreasemonkeyStub(name) {
  7714. + return function() {
  7715. + console.log("%s is not supported.", name);
  7716. + };
  7717. + }
  7718. +
  7719. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  7720. + for (var i = 0, api; api = apis[i]; i++) {
  7721. + window[api] = generateGreasemonkeyStub(api);
  7722. + }
  7723. +})();
  7724. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7725. new file mode 100755
  7726. --- /dev/null
  7727. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7728. @@ -0,0 +1,14 @@
  7729. +<?xml version="1.0" encoding="UTF-8"?>
  7730. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  7731. + <outputs>
  7732. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  7733. + <emit emit_type='prepend'></emit>
  7734. + </output>
  7735. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  7736. + </outputs>
  7737. + <release seq="1">
  7738. + <includes>
  7739. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  7740. + </includes>
  7741. + </release>
  7742. +</grit>
  7743. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  7744. new file mode 100755
  7745. --- /dev/null
  7746. +++ b/components/user_scripts/renderer/script_context.cc
  7747. @@ -0,0 +1,215 @@
  7748. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7749. +// Use of this source code is governed by a BSD-style license that can be
  7750. +// found in the LICENSE file.
  7751. +
  7752. +#include "script_context.h"
  7753. +
  7754. +#include "base/command_line.h"
  7755. +#include "base/containers/flat_set.h"
  7756. +#include "base/containers/contains.h"
  7757. +#include "base/logging.h"
  7758. +#include "base/no_destructor.h"
  7759. +#include "base/stl_util.h"
  7760. +#include "base/strings/string_util.h"
  7761. +#include "base/strings/stringprintf.h"
  7762. +#include "base/values.h"
  7763. +#include "content/public/common/content_switches.h"
  7764. +#include "content/public/common/url_constants.h"
  7765. +#include "content/public/renderer/render_frame.h"
  7766. +#include "../common/constants.h"
  7767. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  7768. +#include "third_party/blink/public/platform/web_security_origin.h"
  7769. +#include "third_party/blink/public/web/web_document.h"
  7770. +#include "third_party/blink/public/web/web_document_loader.h"
  7771. +#include "third_party/blink/public/web/web_local_frame.h"
  7772. +#include "third_party/blink/public/web/web_navigation_params.h"
  7773. +#include "v8/include/v8.h"
  7774. +
  7775. +namespace user_scripts {
  7776. +
  7777. +namespace {
  7778. +
  7779. +GURL GetEffectiveDocumentURL(
  7780. + blink::WebLocalFrame* frame,
  7781. + const GURL& document_url,
  7782. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  7783. + bool allow_inaccessible_parents) {
  7784. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  7785. + switch (match_origin_as_fallback) {
  7786. + case MatchOriginAsFallbackBehavior::kNever:
  7787. + return false;
  7788. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  7789. + return document_url.SchemeIs(url::kAboutScheme);
  7790. + case MatchOriginAsFallbackBehavior::kAlways:
  7791. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  7792. + return document_url.SchemeIs(url::kAboutScheme) ||
  7793. + document_url.SchemeIs(url::kDataScheme);
  7794. + }
  7795. +
  7796. + NOTREACHED();
  7797. + };
  7798. +
  7799. + // If we don't need to consider the origin, we're done.
  7800. + if (!should_consider_origin())
  7801. + return document_url;
  7802. +
  7803. + // Get the "security origin" for the frame. For about: frames, this is the
  7804. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7805. + // https://example.com will have the security origin of https://example.com.
  7806. + // Other frames, like data: frames, will have an opaque origin. For these,
  7807. + // we can get the precursor origin.
  7808. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7809. + const url::Origin frame_origin = web_frame_origin;
  7810. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7811. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7812. +
  7813. + // When there's no valid tuple (which can happen in the case of e.g. a
  7814. + // browser-initiated navigation to an opaque URL), there's no origin to
  7815. + // fallback to. Bail.
  7816. + if (!tuple_or_precursor_tuple.IsValid())
  7817. + return document_url;
  7818. +
  7819. + const url::Origin origin_or_precursor_origin =
  7820. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7821. +
  7822. + if (!allow_inaccessible_parents &&
  7823. + !web_frame_origin.CanAccess(
  7824. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7825. + // The frame can't access its precursor. Bail.
  7826. + return document_url;
  7827. + }
  7828. +
  7829. + // Looks like the initiator origin is an appropriate fallback!
  7830. +
  7831. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7832. + // The easy case! We use the origin directly. We're done.
  7833. + return origin_or_precursor_origin.GetURL();
  7834. + }
  7835. +
  7836. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7837. + match_origin_as_fallback);
  7838. +
  7839. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7840. + // match patterns that are associated with paths as well, not just origins.
  7841. + // For instance, if an extension wants to run on google.com/maps/* with
  7842. + // match_about_blank true, then it should run on about:-scheme frames created
  7843. + // by google.com/maps, but not about:-scheme frames created by google.com
  7844. + // (which is what the precursor tuple origin would be).
  7845. +
  7846. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7847. + // with the same origin as the precursor and return its URL.
  7848. + // Note: This can return the incorrect result, e.g. if a parent frame
  7849. + // navigates a grandchild frame.
  7850. + blink::WebFrame* parent = frame;
  7851. + GURL parent_url;
  7852. + blink::WebDocument parent_document;
  7853. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7854. + do {
  7855. + already_visited_frames.insert(parent);
  7856. + if (parent->Parent())
  7857. + parent = parent->Parent();
  7858. + else
  7859. + parent = parent->Opener();
  7860. +
  7861. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7862. + // https://crbug.com/883526.
  7863. + if (base::Contains(already_visited_frames, parent))
  7864. + return document_url;
  7865. +
  7866. + parent_document = parent && parent->IsWebLocalFrame()
  7867. + ? parent->ToWebLocalFrame()->GetDocument()
  7868. + : blink::WebDocument();
  7869. +
  7870. + // We reached the end of the ancestral chain without finding a valid parent,
  7871. + // or found a remote web frame (in which case, it's a different origin).
  7872. + // Bail and use the original URL.
  7873. + if (parent_document.IsNull())
  7874. + return document_url;
  7875. +
  7876. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7877. + url::Origin(parent->GetSecurityOrigin())
  7878. + .GetTupleOrPrecursorTupleIfOpaque();
  7879. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7880. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7881. + // The parent has a different tuple origin than frame; this could happen
  7882. + // in edge cases where a parent navigates an iframe or popup of a child
  7883. + // frame at a different origin. [1] In this case, bail, since we can't
  7884. + // find a full URL (i.e., one including the path) with the same security
  7885. + // origin to use for the frame in question.
  7886. + // [1] Consider a frame tree like:
  7887. + // <html> <!--example.com-->
  7888. + // <iframe id="a" src="a.com">
  7889. + // <iframe id="b" src="b.com"></iframe>
  7890. + // </iframe>
  7891. + // </html>
  7892. + // Frame "a" is cross-origin from the top-level frame, and so the
  7893. + // example.com top-level frame can't directly access frame "b". However,
  7894. + // it can navigate it through
  7895. + // window.frames[0].frames[0].location.href = 'about:blank';
  7896. + // In that case, the precursor origin tuple origin of frame "b" would be
  7897. + // example.com, but the parent tuple origin is a.com.
  7898. + // Note that usually, this would have bailed earlier with a remote frame,
  7899. + // but it may not if we're at the process limit.
  7900. + return document_url;
  7901. + }
  7902. +
  7903. + parent_url = GURL(parent_document.Url());
  7904. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7905. +
  7906. + DCHECK(!parent_url.is_empty());
  7907. + DCHECK(!parent_document.IsNull());
  7908. +
  7909. + // We should know that the frame can access the parent document (unless we
  7910. + // explicitly allow it not to), since it has the same tuple origin as the
  7911. + // frame, and we checked the frame access above.
  7912. + DCHECK(allow_inaccessible_parents ||
  7913. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7914. + return parent_url;
  7915. +}
  7916. +
  7917. +using FrameToDocumentLoader =
  7918. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7919. +
  7920. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7921. + static base::NoDestructor<FrameToDocumentLoader> map;
  7922. + return *map;
  7923. +}
  7924. +
  7925. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7926. + const blink::WebLocalFrame* frame) {
  7927. + auto& map = FrameDocumentLoaderMap();
  7928. + auto it = map.find(frame);
  7929. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7930. +}
  7931. +
  7932. +} // namespace
  7933. +
  7934. +// static
  7935. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7936. + const blink::WebLocalFrame* frame) {
  7937. + // Normally we would use frame->document().url() to determine the document's
  7938. + // URL, but to decide whether to inject a content script, we use the URL from
  7939. + // the data source. This "quirk" helps prevents content scripts from
  7940. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7941. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7942. + // changes to match the parent document after Gmail document.writes into
  7943. + // it to create the editor.
  7944. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7945. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7946. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7947. +}
  7948. +
  7949. +// static
  7950. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7951. + blink::WebLocalFrame* frame,
  7952. + const GURL& document_url,
  7953. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7954. + // We explicitly allow inaccessible parents here. Extensions should still be
  7955. + // able to inject into a sandboxed iframe if it has access to the embedding
  7956. + // origin.
  7957. + constexpr bool allow_inaccessible_parents = true;
  7958. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7959. + allow_inaccessible_parents);
  7960. +}
  7961. +
  7962. +} // namespace extensions
  7963. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7964. new file mode 100755
  7965. --- /dev/null
  7966. +++ b/components/user_scripts/renderer/script_context.h
  7967. @@ -0,0 +1,69 @@
  7968. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7969. +// Use of this source code is governed by a BSD-style license that can be
  7970. +// found in the LICENSE file.
  7971. +
  7972. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7973. +#define USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7974. +
  7975. +#include <memory>
  7976. +#include <string>
  7977. +#include <utility>
  7978. +#include <vector>
  7979. +
  7980. +#include "base/callback.h"
  7981. +#include "base/compiler_specific.h"
  7982. +#include "base/threading/thread_checker.h"
  7983. +#include "base/unguessable_token.h"
  7984. +#include "../common/script_constants.h"
  7985. +#include "script_injection_callback.h"
  7986. +#include "url/gurl.h"
  7987. +#include "v8/include/v8.h"
  7988. +
  7989. +namespace blink {
  7990. +class WebDocumentLoader;
  7991. +class WebLocalFrame;
  7992. +}
  7993. +
  7994. +namespace content {
  7995. +class RenderFrame;
  7996. +}
  7997. +
  7998. +namespace user_scripts {
  7999. +
  8000. +// Extensions wrapper for a v8::Context.
  8001. +//
  8002. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  8003. +// destroyed that thread.
  8004. +//
  8005. +// Note that ScriptContexts bound to worker threads will not have the full
  8006. +// functionality as those bound to the main RenderThread.
  8007. +class ScriptContext {
  8008. + public:
  8009. + ScriptContext(const ScriptContext&) = delete;
  8010. + ScriptContext& operator=(const ScriptContext&) = delete;
  8011. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  8012. + // vaguely ScriptContext related, there's enough here that they probably
  8013. + // warrant another class or utility file.
  8014. +
  8015. + // Utility to get the URL we will match against for a frame. If the frame has
  8016. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  8017. + // The returned URL may be invalid.
  8018. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  8019. +
  8020. + // Used to determine the "effective" URL for extension script injection.
  8021. + // If |document_url| is an about: or data: URL, returns the URL of the first
  8022. + // frame without an about: or data: URL that matches the initiator origin.
  8023. + // This may not be the immediate parent. Returns |document_url| if it is not
  8024. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  8025. + // or if a suitable parent cannot be found.
  8026. + // Considers parent contexts that cannot be accessed (as is the case for
  8027. + // sandboxed frames).
  8028. + static GURL GetEffectiveDocumentURLForInjection(
  8029. + blink::WebLocalFrame* frame,
  8030. + const GURL& document_url,
  8031. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  8032. +};
  8033. +
  8034. +} // namespace extensions
  8035. +
  8036. +#endif // USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  8037. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  8038. new file mode 100755
  8039. --- /dev/null
  8040. +++ b/components/user_scripts/renderer/script_injection.cc
  8041. @@ -0,0 +1,343 @@
  8042. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8043. +// Use of this source code is governed by a BSD-style license that can be
  8044. +// found in the LICENSE file.
  8045. +
  8046. +#include "script_injection.h"
  8047. +
  8048. +#include <map>
  8049. +#include <utility>
  8050. +
  8051. +#include "base/bind.h"
  8052. +#include "base/feature_list.h"
  8053. +#include "base/lazy_instance.h"
  8054. +#include "base/metrics/histogram_macros.h"
  8055. +#include "base/timer/elapsed_timer.h"
  8056. +#include "base/values.h"
  8057. +#include "base/logging.h"
  8058. +#include "content/public/renderer/render_frame.h"
  8059. +#include "content/public/renderer/render_frame_observer.h"
  8060. +#include "content/public/renderer/v8_value_converter.h"
  8061. +#include "../common/host_id.h"
  8062. +#include "script_injection_callback.h"
  8063. +#include "scripts_run_info.h"
  8064. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  8065. +#include "third_party/blink/public/platform/web_security_origin.h"
  8066. +#include "third_party/blink/public/platform/web_string.h"
  8067. +#include "third_party/blink/public/web/web_document.h"
  8068. +#include "third_party/blink/public/web/web_local_frame.h"
  8069. +#include "third_party/blink/public/web/web_script_source.h"
  8070. +#include "url/gurl.h"
  8071. +
  8072. +namespace user_scripts {
  8073. +
  8074. +namespace {
  8075. +
  8076. +using IsolatedWorldMap = std::map<std::string, int>;
  8077. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  8078. + LAZY_INSTANCE_INITIALIZER;
  8079. +
  8080. +const int64_t kInvalidRequestId = -1;
  8081. +
  8082. +// Gets the isolated world ID to use for the given |injection_host|. If no
  8083. +// isolated world has been created for that |injection_host| one will be created
  8084. +// and initialized.
  8085. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  8086. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  8087. +
  8088. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8089. +
  8090. + int id = 0;
  8091. + const std::string& key = injection_host->id().id();
  8092. + auto iter = isolated_worlds.find(key);
  8093. + if (iter != isolated_worlds.end()) {
  8094. + id = iter->second;
  8095. + } else {
  8096. + id = g_next_isolated_world_id++;
  8097. + // This map will tend to pile up over time, but realistically, you're never
  8098. + // going to have enough injection hosts for it to matter.
  8099. + isolated_worlds[key] = id;
  8100. + }
  8101. +
  8102. + blink::WebIsolatedWorldInfo info;
  8103. + info.security_origin =
  8104. + blink::WebSecurityOrigin::Create(injection_host->url());
  8105. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  8106. + info.stable_id = blink::WebString::FromUTF8(key);
  8107. +
  8108. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  8109. + if (csp)
  8110. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  8111. +
  8112. + // Even though there may be an existing world for this |injection_host|'s key,
  8113. + // the properties may have changed (e.g. due to an extension update).
  8114. + // Overwrite any existing entries.
  8115. + blink::SetIsolatedWorldInfo(id, info);
  8116. +
  8117. + return id;
  8118. +}
  8119. +
  8120. +// This class manages its own lifetime.
  8121. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  8122. + public:
  8123. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  8124. + : ScriptInjectionCallback(
  8125. + base::BindOnce(&TimedScriptInjectionCallback::OnCompleted,
  8126. + base::Unretained(this))),
  8127. + injection_(injection) {}
  8128. + ~TimedScriptInjectionCallback() override {}
  8129. +
  8130. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  8131. + if (injection_) {
  8132. + base::TimeTicks timestamp(base::TimeTicks::Now());
  8133. + absl::optional<base::TimeDelta> elapsed;
  8134. + // If the script will never execute (such as if the context is destroyed),
  8135. + // willExecute() will not be called, but OnCompleted() will. Only log a
  8136. + // time for execution if the script, in fact, executed.
  8137. + if (!start_time_.is_null())
  8138. + elapsed = timestamp - start_time_;
  8139. + injection_->OnJsInjectionCompleted(result, elapsed);
  8140. + }
  8141. + }
  8142. +
  8143. + void WillExecute() override {
  8144. + start_time_ = base::TimeTicks::Now();
  8145. + }
  8146. +
  8147. + private:
  8148. + base::WeakPtr<ScriptInjection> injection_;
  8149. + base::TimeTicks start_time_;
  8150. +};
  8151. +
  8152. +} // namespace
  8153. +
  8154. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  8155. +// false.
  8156. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  8157. + public:
  8158. + FrameWatcher(const FrameWatcher&) = delete;
  8159. + FrameWatcher& operator=(const FrameWatcher&) = delete;
  8160. + FrameWatcher(content::RenderFrame* render_frame,
  8161. + ScriptInjection* injection)
  8162. + : content::RenderFrameObserver(render_frame),
  8163. + injection_(injection) {}
  8164. + ~FrameWatcher() override {}
  8165. +
  8166. + private:
  8167. + void WillDetach() override { injection_->invalidate_render_frame(); }
  8168. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  8169. +
  8170. + ScriptInjection* injection_;
  8171. +};
  8172. +
  8173. +// static
  8174. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  8175. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8176. +
  8177. + for (const auto& iter : isolated_worlds) {
  8178. + if (iter.second == isolated_world_id)
  8179. + return iter.first;
  8180. + }
  8181. + return std::string();
  8182. +}
  8183. +
  8184. +// static
  8185. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  8186. + g_isolated_worlds.Get().erase(host_id);
  8187. +}
  8188. +
  8189. +ScriptInjection::ScriptInjection(
  8190. + std::unique_ptr<ScriptInjector> injector,
  8191. + content::RenderFrame* render_frame,
  8192. + std::unique_ptr<const InjectionHost> injection_host,
  8193. + UserScript::RunLocation run_location,
  8194. + bool log_activity)
  8195. + : injector_(std::move(injector)),
  8196. + render_frame_(render_frame),
  8197. + injection_host_(std::move(injection_host)),
  8198. + run_location_(run_location),
  8199. + request_id_(kInvalidRequestId),
  8200. + complete_(false),
  8201. + did_inject_js_(false),
  8202. + log_activity_(log_activity),
  8203. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  8204. + CHECK(injection_host_.get());
  8205. +}
  8206. +
  8207. +ScriptInjection::~ScriptInjection() {
  8208. + if (!complete_)
  8209. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  8210. +}
  8211. +
  8212. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  8213. + UserScript::RunLocation current_location,
  8214. + ScriptsRunInfo* scripts_run_info,
  8215. + CompletionCallback async_completion_callback) {
  8216. + if (current_location < run_location_)
  8217. + return INJECTION_WAITING; // Wait for the right location.
  8218. +
  8219. + if (request_id_ != kInvalidRequestId) {
  8220. + // We're waiting for permission right now, try again later.
  8221. + return INJECTION_WAITING;
  8222. + }
  8223. +
  8224. + if (!injection_host_) {
  8225. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8226. + return INJECTION_FINISHED; // We're done.
  8227. + }
  8228. +
  8229. + InjectionResult result = Inject(scripts_run_info);
  8230. + // If the injection is blocked, we need to set the manager so we can
  8231. + // notify it upon completion.
  8232. + if (result == INJECTION_BLOCKED)
  8233. + async_completion_callback_ = std::move(async_completion_callback);
  8234. + return result;
  8235. +}
  8236. +
  8237. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  8238. + ScriptsRunInfo* scripts_run_info) {
  8239. + if (!injection_host_) {
  8240. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8241. + return INJECTION_FINISHED;
  8242. + }
  8243. +
  8244. + return Inject(scripts_run_info);
  8245. +}
  8246. +
  8247. +void ScriptInjection::OnHostRemoved() {
  8248. + injection_host_.reset(nullptr);
  8249. +}
  8250. +
  8251. +void ScriptInjection::NotifyWillNotInject(
  8252. + ScriptInjector::InjectFailureReason reason) {
  8253. + complete_ = true;
  8254. + injector_->OnWillNotInject(reason, render_frame_);
  8255. +}
  8256. +
  8257. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  8258. + ScriptsRunInfo* scripts_run_info) {
  8259. + DCHECK(injection_host_);
  8260. + //DCHECK(scripts_run_info);
  8261. + DCHECK(!complete_);
  8262. + bool should_inject_js = injector_->ShouldInjectJs(
  8263. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  8264. + bool should_inject_css = injector_->ShouldInjectCss(
  8265. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  8266. +
  8267. + // This can happen if the extension specified a script to
  8268. + // be run in multiple rules, and the script has already run.
  8269. + // See crbug.com/631247.
  8270. + if (!should_inject_js && !should_inject_css) {
  8271. + return INJECTION_FINISHED;
  8272. + }
  8273. +
  8274. + if (should_inject_js)
  8275. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  8276. + &(scripts_run_info->num_js));
  8277. + if (should_inject_css)
  8278. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  8279. + &(scripts_run_info->num_css));
  8280. +
  8281. + complete_ = did_inject_js_ || !should_inject_js;
  8282. +
  8283. + if (complete_) {
  8284. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8285. + render_frame_);
  8286. + } else {
  8287. + ++scripts_run_info->num_blocking_js;
  8288. + }
  8289. +
  8290. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  8291. +}
  8292. +
  8293. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  8294. + size_t* num_injected_js_scripts) {
  8295. + DCHECK(!did_inject_js_);
  8296. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  8297. + run_location_, executing_scripts, num_injected_js_scripts);
  8298. + DCHECK(!sources.empty());
  8299. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  8300. + bool is_user_gesture = injector_->IsUserGesture();
  8301. +
  8302. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  8303. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  8304. +
  8305. + base::ElapsedTimer exec_timer;
  8306. +
  8307. + // For content scripts executing during page load, we run them asynchronously
  8308. + // in order to reduce UI jank experienced by the user. (We don't do this for
  8309. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  8310. + // run, so we run them as soon as we can.)
  8311. + // Note: We could potentially also run deferred and browser-driven scripts
  8312. + // asynchronously; however, these are rare enough that there probably isn't
  8313. + // UI jank. If this changes, we can update this.
  8314. + bool should_execute_asynchronously =
  8315. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  8316. + (run_location_ == UserScript::DOCUMENT_END ||
  8317. + run_location_ == UserScript::DOCUMENT_IDLE);
  8318. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  8319. + should_execute_asynchronously
  8320. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  8321. + : blink::WebLocalFrame::kSynchronous;
  8322. +
  8323. + render_frame_->GetWebFrame()->RequestExecuteScript(
  8324. + world_id, sources, is_user_gesture,
  8325. + execution_option, callback.release(),
  8326. + blink::BackForwardCacheAware::kPossiblyDisallow,
  8327. + blink::WebLocalFrame::PromiseBehavior::kDontWait);
  8328. +}
  8329. +
  8330. +void ScriptInjection::OnJsInjectionCompleted(
  8331. + const std::vector<v8::Local<v8::Value>>& results,
  8332. + absl::optional<base::TimeDelta> elapsed) {
  8333. + DCHECK(!did_inject_js_);
  8334. +
  8335. + bool expects_results = injector_->ExpectsResults();
  8336. + if (expects_results) {
  8337. + if (!results.empty() && !results[0].IsEmpty()) {
  8338. + // Right now, we only support returning single results (per frame).
  8339. + // It's safe to always use the main world context when converting
  8340. + // here. V8ValueConverterImpl shouldn't actually care about the
  8341. + // context scope, and it switches to v8::Object's creation context
  8342. + // when encountered.
  8343. + v8::Local<v8::Context> context =
  8344. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  8345. + execution_result_ =
  8346. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  8347. + }
  8348. + if (!execution_result_.get())
  8349. + execution_result_ = std::make_unique<base::Value>();
  8350. + }
  8351. + did_inject_js_ = true;
  8352. +
  8353. + // If |async_completion_callback_| is set, it means the script finished
  8354. + // asynchronously, and we should run it.
  8355. + if (!async_completion_callback_.is_null()) {
  8356. + complete_ = true;
  8357. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8358. + render_frame_);
  8359. + // Warning: this object can be destroyed after this line!
  8360. + std::move(async_completion_callback_).Run(this);
  8361. + }
  8362. +}
  8363. +
  8364. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  8365. + size_t* num_injected_stylesheets) {
  8366. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  8367. + run_location_, injected_stylesheets, num_injected_stylesheets);
  8368. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  8369. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  8370. + absl::optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  8371. + blink::WebCssOrigin blink_css_origin =
  8372. + css_origin && *css_origin == CSS_ORIGIN_USER
  8373. + ? blink::WebCssOrigin::kUser
  8374. + : blink::WebCssOrigin::kAuthor;
  8375. + blink::WebStyleSheetKey style_sheet_key;
  8376. + if (const absl::optional<std::string>& injection_key =
  8377. + injector_->GetInjectionKey())
  8378. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  8379. + for (const blink::WebString& css : css_sources)
  8380. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  8381. + blink_css_origin);
  8382. +}
  8383. +
  8384. +} // namespace extensions
  8385. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  8386. new file mode 100755
  8387. --- /dev/null
  8388. +++ b/components/user_scripts/renderer/script_injection.h
  8389. @@ -0,0 +1,154 @@
  8390. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8391. +// Use of this source code is governed by a BSD-style license that can be
  8392. +// found in the LICENSE file.
  8393. +
  8394. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8395. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8396. +
  8397. +#include <stdint.h>
  8398. +
  8399. +#include <memory>
  8400. +#include <vector>
  8401. +
  8402. +#include "base/callback.h"
  8403. +#include "base/memory/weak_ptr.h"
  8404. +#include "../common/user_script.h"
  8405. +#include "injection_host.h"
  8406. +#include "script_injector.h"
  8407. +
  8408. +struct HostID;
  8409. +
  8410. +namespace content {
  8411. +class RenderFrame;
  8412. +}
  8413. +
  8414. +namespace v8 {
  8415. +class Value;
  8416. +template <class T> class Local;
  8417. +}
  8418. +
  8419. +namespace user_scripts {
  8420. +struct ScriptsRunInfo;
  8421. +
  8422. +// A script wrapper which is aware of whether or not it is allowed to execute,
  8423. +// and contains the implementation to do so.
  8424. +class ScriptInjection {
  8425. + public:
  8426. + ScriptInjection(const ScriptInjection&) = delete;
  8427. + ScriptInjection& operator=(const ScriptInjection&) = delete;
  8428. + enum InjectionResult {
  8429. + INJECTION_FINISHED,
  8430. + INJECTION_BLOCKED,
  8431. + INJECTION_WAITING
  8432. + };
  8433. +
  8434. + using CompletionCallback = base::OnceCallback<void(ScriptInjection*)>;
  8435. +
  8436. + // Return the id of the injection host associated with the given world.
  8437. + static std::string GetHostIdForIsolatedWorld(int world_id);
  8438. +
  8439. + // Remove the isolated world associated with the given injection host.
  8440. + static void RemoveIsolatedWorld(const std::string& host_id);
  8441. +
  8442. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  8443. + content::RenderFrame* render_frame,
  8444. + std::unique_ptr<const InjectionHost> injection_host,
  8445. + UserScript::RunLocation run_location,
  8446. + bool log_activity);
  8447. + ~ScriptInjection();
  8448. +
  8449. + // Try to inject the script at the |current_location|. This returns
  8450. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  8451. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  8452. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  8453. + // for permission purposes or because |current_location| is not the designated
  8454. + // |run_location_|).
  8455. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  8456. + // called upon completion.
  8457. + InjectionResult TryToInject(
  8458. + UserScript::RunLocation current_location,
  8459. + ScriptsRunInfo* scripts_run_info,
  8460. + CompletionCallback async_completion_callback);
  8461. +
  8462. + // Called when permission for the given injection has been granted.
  8463. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  8464. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  8465. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  8466. +
  8467. + // Resets the pointer of the injection host when the host is gone.
  8468. + void OnHostRemoved();
  8469. +
  8470. + void invalidate_render_frame() { render_frame_ = nullptr; }
  8471. +
  8472. + // Accessors.
  8473. + content::RenderFrame* render_frame() const { return render_frame_; }
  8474. + const HostID& host_id() const { return injection_host_->id(); }
  8475. + int64_t request_id() const { return request_id_; }
  8476. +
  8477. + // Called when JS injection for the given frame has been completed or
  8478. + // cancelled.
  8479. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  8480. + absl::optional<base::TimeDelta> elapsed);
  8481. +
  8482. + private:
  8483. + class FrameWatcher;
  8484. +
  8485. + // Sends a message to the browser to request permission to inject.
  8486. + void RequestPermissionFromBrowser();
  8487. +
  8488. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  8489. + // otherwise INJECTION_BLOCKED.
  8490. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  8491. +
  8492. + // Inject any JS scripts into the frame for the injection.
  8493. + void InjectJs(std::set<std::string>* executing_scripts,
  8494. + size_t* num_injected_js_scripts);
  8495. +
  8496. + // Inject any CSS source into the frame for the injection.
  8497. + void InjectCss(std::set<std::string>* injected_stylesheets,
  8498. + size_t* num_injected_stylesheets);
  8499. +
  8500. + // Notify that we will not inject, and mark it as acknowledged.
  8501. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  8502. +
  8503. + // The injector for this injection.
  8504. + std::unique_ptr<ScriptInjector> injector_;
  8505. +
  8506. + // The RenderFrame into which this should inject the script.
  8507. + content::RenderFrame* render_frame_;
  8508. +
  8509. + // The associated injection host.
  8510. + std::unique_ptr<const InjectionHost> injection_host_;
  8511. +
  8512. + // The location in the document load at which we inject the script.
  8513. + UserScript::RunLocation run_location_;
  8514. +
  8515. + // This injection's request id. This will be -1 unless the injection is
  8516. + // currently waiting on permission.
  8517. + int64_t request_id_;
  8518. +
  8519. + // Whether or not the injection is complete, either via injecting the script
  8520. + // or because it will never complete.
  8521. + bool complete_;
  8522. +
  8523. + // Whether or not the injection successfully injected JS.
  8524. + bool did_inject_js_;
  8525. +
  8526. + // Whether or not we should log dom activity for this injection.
  8527. + bool log_activity_;
  8528. +
  8529. + // Results storage.
  8530. + std::unique_ptr<base::Value> execution_result_;
  8531. +
  8532. + // The callback to run upon completing asynchronously.
  8533. + CompletionCallback async_completion_callback_;
  8534. +
  8535. + // A helper class to hold the render frame and watch for its deletion.
  8536. + std::unique_ptr<FrameWatcher> frame_watcher_;
  8537. +
  8538. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  8539. +};
  8540. +
  8541. +} // namespace extensions
  8542. +
  8543. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8544. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  8545. new file mode 100755
  8546. --- /dev/null
  8547. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  8548. @@ -0,0 +1,25 @@
  8549. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8550. +// Use of this source code is governed by a BSD-style license that can be
  8551. +// found in the LICENSE file.
  8552. +
  8553. +#include "script_injection_callback.h"
  8554. +
  8555. +#include "third_party/blink/public/platform/web_vector.h"
  8556. +
  8557. +namespace user_scripts {
  8558. +
  8559. +ScriptInjectionCallback::ScriptInjectionCallback(
  8560. + CompleteCallback injection_completed_callback)
  8561. + : injection_completed_callback_(std::move(injection_completed_callback)) {}
  8562. +
  8563. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  8564. +}
  8565. +
  8566. +void ScriptInjectionCallback::Completed(
  8567. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  8568. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  8569. + std::move(injection_completed_callback_).Run(stl_result);
  8570. + delete this;
  8571. +}
  8572. +
  8573. +} // namespace extensions
  8574. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  8575. new file mode 100755
  8576. --- /dev/null
  8577. +++ b/components/user_scripts/renderer/script_injection_callback.h
  8578. @@ -0,0 +1,38 @@
  8579. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8580. +// Use of this source code is governed by a BSD-style license that can be
  8581. +// found in the LICENSE file.
  8582. +
  8583. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8584. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8585. +
  8586. +#include <vector>
  8587. +
  8588. +#include "base/callback.h"
  8589. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  8590. +#include "v8/include/v8.h"
  8591. +
  8592. +namespace user_scripts {
  8593. +
  8594. +// A wrapper around a callback to notify a script injection when injection
  8595. +// completes.
  8596. +// This class manages its own lifetime.
  8597. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  8598. + public:
  8599. + ScriptInjectionCallback(const ScriptInjectionCallback&) = delete;
  8600. + ScriptInjectionCallback& operator=(const ScriptInjectionCallback&) = delete;
  8601. + using CompleteCallback =
  8602. + base::OnceCallback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  8603. +
  8604. + explicit ScriptInjectionCallback(
  8605. + CompleteCallback injection_completed_callback);
  8606. + ~ScriptInjectionCallback() override;
  8607. +
  8608. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  8609. +
  8610. + private:
  8611. + CompleteCallback injection_completed_callback_;
  8612. +};
  8613. +
  8614. +} // namespace extensions
  8615. +
  8616. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8617. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  8618. new file mode 100755
  8619. --- /dev/null
  8620. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  8621. @@ -0,0 +1,417 @@
  8622. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8623. +// Use of this source code is governed by a BSD-style license that can be
  8624. +// found in the LICENSE file.
  8625. +
  8626. +#include "script_injection_manager.h"
  8627. +
  8628. +#include <memory>
  8629. +#include <utility>
  8630. +
  8631. +#include "base/auto_reset.h"
  8632. +#include "base/bind.h"
  8633. +#include "base/feature_list.h"
  8634. +#include "base/memory/weak_ptr.h"
  8635. +#include "base/threading/thread_task_runner_handle.h"
  8636. +#include "base/values.h"
  8637. +#include "base/logging.h"
  8638. +#include "content/public/renderer/render_frame.h"
  8639. +#include "content/public/renderer/render_frame_observer.h"
  8640. +#include "content/public/renderer/render_thread.h"
  8641. +#include "extension_frame_helper.h"
  8642. +#include "../common/host_id.h"
  8643. +#include "script_injection.h"
  8644. +#include "scripts_run_info.h"
  8645. +#include "web_ui_injection_host.h"
  8646. +#include "ipc/ipc_message_macros.h"
  8647. +#include "third_party/blink/public/platform/web_url_error.h"
  8648. +#include "third_party/blink/public/web/web_document.h"
  8649. +#include "third_party/blink/public/web/web_frame.h"
  8650. +#include "third_party/blink/public/web/web_local_frame.h"
  8651. +#include "third_party/blink/public/web/web_view.h"
  8652. +#include "url/gurl.h"
  8653. +#include "../common/user_scripts_features.h"
  8654. +
  8655. +namespace user_scripts {
  8656. +
  8657. +namespace {
  8658. +
  8659. +// The length of time to wait after the DOM is complete to try and run user
  8660. +// scripts.
  8661. +const int kScriptIdleTimeoutInMs = 200;
  8662. +
  8663. +// Returns the RunLocation that follows |run_location|.
  8664. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  8665. + switch (run_location) {
  8666. + case UserScript::DOCUMENT_START:
  8667. + return UserScript::DOCUMENT_END;
  8668. + case UserScript::DOCUMENT_END:
  8669. + return UserScript::DOCUMENT_IDLE;
  8670. + case UserScript::DOCUMENT_IDLE:
  8671. + return UserScript::RUN_LOCATION_LAST;
  8672. + case UserScript::UNDEFINED:
  8673. + case UserScript::RUN_DEFERRED:
  8674. + case UserScript::BROWSER_DRIVEN:
  8675. + case UserScript::RUN_LOCATION_LAST:
  8676. + break;
  8677. + }
  8678. + NOTREACHED();
  8679. + return UserScript::RUN_LOCATION_LAST;
  8680. +}
  8681. +
  8682. +} // namespace
  8683. +
  8684. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  8685. + public:
  8686. + RFOHelper(content::RenderFrame* render_frame,
  8687. + ScriptInjectionManager* manager);
  8688. + ~RFOHelper() override;
  8689. +
  8690. + // commit @9f2aac4
  8691. + void Initialize();
  8692. +
  8693. + private:
  8694. + // RenderFrameObserver implementation.
  8695. + void DidCreateNewDocument() override;
  8696. + void DidCreateDocumentElement() override;
  8697. + void DidFailProvisionalLoad() override;
  8698. + void DidDispatchDOMContentLoadedEvent() override;
  8699. + void WillDetach() override;
  8700. + void OnDestruct() override;
  8701. + void OnStop() override;
  8702. +
  8703. + // Tells the ScriptInjectionManager to run tasks associated with
  8704. + // document_idle.
  8705. + void RunIdle();
  8706. +
  8707. + void StartInjectScripts(UserScript::RunLocation run_location);
  8708. +
  8709. + // Indicate that the frame is no longer valid because it is starting
  8710. + // a new load or closing.
  8711. + void InvalidateAndResetFrame(bool force_reset);
  8712. +
  8713. + // The owning ScriptInjectionManager.
  8714. + ScriptInjectionManager* manager_;
  8715. +
  8716. + bool should_run_idle_ = true; // commit @9f2aac4
  8717. +
  8718. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  8719. +};
  8720. +
  8721. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  8722. + ScriptInjectionManager* manager)
  8723. + : content::RenderFrameObserver(render_frame),
  8724. + manager_(manager),
  8725. + should_run_idle_(true) {}
  8726. +
  8727. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  8728. +}
  8729. +
  8730. +
  8731. +void ScriptInjectionManager::RFOHelper::Initialize() {
  8732. + // Set up for the initial empty document, for which the Document created
  8733. + // events do not happen as it's already present.
  8734. + DidCreateNewDocument();
  8735. + // The initial empty document for a main frame may have scripts attached to it
  8736. + // but we do not want to invalidate the frame and lose them when the next
  8737. + // document loads. For example the IncognitoApiTest.IncognitoSplitMode test
  8738. + // does `chrome.tabs.create()` with a script to be run, which is added to the
  8739. + // frame before it navigates, so it needs to be preserved. However scripts in
  8740. + // child frames are expected to be run inside the initial empty document. For
  8741. + // example the ExecuteScriptApiTest.FrameWithHttp204 test creates a child
  8742. + // frame at about:blank and expects to run injected scripts inside it.
  8743. + // This is all quite inconsistent however tests both depend on us queuing and
  8744. + // not queueing the DOCUMENT_START events in the initial empty document.
  8745. + if (!render_frame()->IsMainFrame()) {
  8746. + DidCreateDocumentElement();
  8747. + }
  8748. +}
  8749. +
  8750. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  8751. + // A new document is going to be shown, so invalidate the old document state.
  8752. + // Don't force-reset the frame, because it is possible that a script injection
  8753. + // was scheduled before the page was loaded, e.g. by navigating to a
  8754. + // javascript: URL before the page has loaded.
  8755. + constexpr bool kForceReset = false;
  8756. + InvalidateAndResetFrame(kForceReset);
  8757. +}
  8758. +
  8759. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  8760. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8761. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  8762. +
  8763. + ExtensionFrameHelper::Get(render_frame())
  8764. + ->ScheduleAtDocumentStart(
  8765. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8766. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  8767. +}
  8768. +
  8769. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  8770. + auto it = manager_->frame_statuses_.find(render_frame());
  8771. + if (it != manager_->frame_statuses_.end() &&
  8772. + it->second == UserScript::DOCUMENT_START) {
  8773. + // Since the provisional load failed, the frame stays at its previous loaded
  8774. + // state and origin (or the parent's origin for new/about:blank frames).
  8775. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  8776. + // done loading, and avoid any deadlock in the system.
  8777. + //
  8778. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  8779. + // injections closely follow the DOMContentLoaded (and onload) events, which
  8780. + // are not triggered after a failed provisional load.
  8781. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  8782. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  8783. + constexpr bool kForceReset = true;
  8784. + InvalidateAndResetFrame(kForceReset);
  8785. + should_run_idle_ = false;
  8786. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  8787. + }
  8788. +}
  8789. +
  8790. +void ScriptInjectionManager::RFOHelper::DidDispatchDOMContentLoadedEvent() {
  8791. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8792. + LOG(INFO) << "UserScripts: DidDispatchDOMContentLoadedEvent -> DOCUMENT_END";
  8793. +
  8794. + DCHECK(content::RenderThread::Get());
  8795. + ExtensionFrameHelper::Get(render_frame())
  8796. + ->ScheduleAtDocumentEnd(
  8797. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8798. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8799. +
  8800. + // We try to run idle in two places: a delayed task here and in response to
  8801. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidDispatchDOMContentLoadedEvent()
  8802. + // corresponds to completing the document's load, whereas
  8803. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8804. + // subresources' load (but before the window.onload event). We don't want to
  8805. + // hold up script injection for a particularly slow subresource, so we set a
  8806. + // delayed task from here - but if we finish everything before that point
  8807. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8808. + // keep waiting.
  8809. + render_frame()
  8810. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8811. + ->PostDelayedTask(
  8812. + FROM_HERE,
  8813. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8814. + weak_factory_.GetWeakPtr()),
  8815. + base::Milliseconds(kScriptIdleTimeoutInMs));
  8816. +
  8817. + ExtensionFrameHelper::Get(render_frame())
  8818. + ->ScheduleAtDocumentIdle(
  8819. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8820. + weak_factory_.GetWeakPtr()));
  8821. +}
  8822. +
  8823. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8824. + // The frame is closing - invalidate.
  8825. + constexpr bool kForceReset = true;
  8826. + InvalidateAndResetFrame(kForceReset);
  8827. +}
  8828. +
  8829. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8830. + manager_->RemoveObserver(this);
  8831. +}
  8832. +
  8833. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8834. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8835. + // extension to avoid keeping the frame in a START state indefinitely which
  8836. + // leads to deadlocks.
  8837. + DidFailProvisionalLoad();
  8838. +}
  8839. +
  8840. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8841. + // Only notify the manager if the frame hasn't already had idle run since the
  8842. + // task to RunIdle() was posted.
  8843. + if (should_run_idle_) {
  8844. + should_run_idle_ = false;
  8845. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8846. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8847. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8848. + }
  8849. +}
  8850. +
  8851. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8852. + UserScript::RunLocation run_location) {
  8853. + manager_->StartInjectScripts(render_frame(), run_location);
  8854. +}
  8855. +
  8856. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8857. + bool force_reset) {
  8858. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8859. + weak_factory_.InvalidateWeakPtrs();
  8860. + // We reset to inject on idle, because the frame can be reused (in the case of
  8861. + // navigation).
  8862. + should_run_idle_ = true;
  8863. +
  8864. + // Reset the frame if either |force_reset| is true, or if the manager is
  8865. + // keeping track of the state of the frame (in which case we need to clean it
  8866. + // up).
  8867. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8868. + manager_->InvalidateForFrame(render_frame());
  8869. +}
  8870. +
  8871. +ScriptInjectionManager::ScriptInjectionManager(
  8872. + UserScriptSetManager* user_script_set_manager)
  8873. + : user_script_set_manager_(user_script_set_manager),
  8874. + user_script_set_manager_observation_(this) {
  8875. + user_script_set_manager_observation_.Observe(user_script_set_manager_);
  8876. +}
  8877. +
  8878. +ScriptInjectionManager::~ScriptInjectionManager() {
  8879. + for (const auto& injection : pending_injections_)
  8880. + injection->invalidate_render_frame();
  8881. + for (const auto& injection : running_injections_)
  8882. + injection->invalidate_render_frame();
  8883. +}
  8884. +
  8885. +void ScriptInjectionManager::OnRenderFrameCreated(
  8886. + content::RenderFrame* render_frame) {
  8887. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8888. + rfo_helpers_.back()->Initialize(); // commit @9f2aac4
  8889. +}
  8890. +
  8891. +void ScriptInjectionManager::OnInjectionFinished(
  8892. + ScriptInjection* injection) {
  8893. + auto iter =
  8894. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8895. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8896. + return injection == mode.get();
  8897. + });
  8898. + if (iter != running_injections_.end())
  8899. + running_injections_.erase(iter);
  8900. +}
  8901. +
  8902. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8903. + const std::set<HostID>& changed_hosts) {
  8904. + for (auto iter = pending_injections_.begin();
  8905. + iter != pending_injections_.end();) {
  8906. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8907. + iter = pending_injections_.erase(iter);
  8908. + else
  8909. + ++iter;
  8910. + }
  8911. +}
  8912. +
  8913. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8914. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8915. + if (iter->get() == helper) {
  8916. + rfo_helpers_.erase(iter);
  8917. + break;
  8918. + }
  8919. + }
  8920. +}
  8921. +
  8922. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8923. + // If the frame invalidated is the frame being injected into, we need to
  8924. + // note it.
  8925. + active_injection_frames_.erase(frame);
  8926. +
  8927. + for (auto iter = pending_injections_.begin();
  8928. + iter != pending_injections_.end();) {
  8929. + if ((*iter)->render_frame() == frame)
  8930. + iter = pending_injections_.erase(iter);
  8931. + else
  8932. + ++iter;
  8933. + }
  8934. +
  8935. + frame_statuses_.erase(frame);
  8936. +}
  8937. +
  8938. +void ScriptInjectionManager::StartInjectScripts(
  8939. + content::RenderFrame* frame,
  8940. + UserScript::RunLocation run_location) {
  8941. + auto iter = frame_statuses_.find(frame);
  8942. + // We also don't execute if we detect that the run location is somehow out of
  8943. + // order. This can happen if:
  8944. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8945. + // - The run location reported doesn't immediately follow the previous
  8946. + // reported run location.
  8947. + // We don't want to run because extensions may have requirements that scripts
  8948. + // running in an earlier run location have run by the time a later script
  8949. + // runs. Better to just not run.
  8950. + // Note that we check run_location > NextRunLocation() in the second clause
  8951. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8952. + // can happen multiple times, so we can receive earlier/equal run locations.
  8953. + if ((iter == frame_statuses_.end() &&
  8954. + run_location != UserScript::DOCUMENT_START) ||
  8955. + (iter != frame_statuses_.end() &&
  8956. + run_location > NextRunLocation(iter->second))) {
  8957. + // We also invalidate the frame, because the run order of pending injections
  8958. + // may also be bad.
  8959. + InvalidateForFrame(frame);
  8960. + return;
  8961. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8962. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8963. + // multiple times. Ignore the subsequent signals.
  8964. + return;
  8965. + }
  8966. +
  8967. + // Otherwise, all is right in the world, and we can get on with the
  8968. + // injections!
  8969. + frame_statuses_[frame] = run_location;
  8970. + InjectScripts(frame, run_location);
  8971. +}
  8972. +
  8973. +void ScriptInjectionManager::InjectScripts(
  8974. + content::RenderFrame* frame,
  8975. + UserScript::RunLocation run_location) {
  8976. + // Find any injections that want to run on the given frame.
  8977. + ScriptInjectionVector frame_injections;
  8978. + for (auto iter = pending_injections_.begin();
  8979. + iter != pending_injections_.end();) {
  8980. + if ((*iter)->render_frame() == frame) {
  8981. + frame_injections.push_back(std::move(*iter));
  8982. + iter = pending_injections_.erase(iter);
  8983. + } else {
  8984. + ++iter;
  8985. + }
  8986. + }
  8987. +
  8988. + // Add any injections for user scripts.
  8989. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  8990. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  8991. + run_location);
  8992. +
  8993. + // Note that we are running in |frame|.
  8994. + active_injection_frames_.insert(frame);
  8995. +
  8996. + ScriptsRunInfo scripts_run_info(frame, run_location);
  8997. +
  8998. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  8999. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  9000. + // (if a script removes its own frame, for example). If this happens, abort.
  9001. + if (!active_injection_frames_.count(frame))
  9002. + break;
  9003. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  9004. + iter = frame_injections.erase(iter);
  9005. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  9006. + }
  9007. +
  9008. + // We are done running in the frame.
  9009. + active_injection_frames_.erase(frame);
  9010. +
  9011. + scripts_run_info.LogRun(activity_logging_enabled_);
  9012. +}
  9013. +
  9014. +void ScriptInjectionManager::TryToInject(
  9015. + std::unique_ptr<ScriptInjection> injection,
  9016. + UserScript::RunLocation run_location,
  9017. + ScriptsRunInfo* scripts_run_info) {
  9018. + // Try to inject the script. If the injection is waiting (i.e., for
  9019. + // permission), add it to the list of pending injections. If the injection
  9020. + // has blocked, add it to the list of running injections.
  9021. + // The Unretained below is safe because this object owns all the
  9022. + // ScriptInjections, so is guaranteed to outlive them.
  9023. + switch (injection->TryToInject(
  9024. + run_location, scripts_run_info,
  9025. + base::BindOnce(&ScriptInjectionManager::OnInjectionFinished,
  9026. + base::Unretained(this)))) {
  9027. + case ScriptInjection::INJECTION_WAITING:
  9028. + pending_injections_.push_back(std::move(injection));
  9029. + break;
  9030. + case ScriptInjection::INJECTION_BLOCKED:
  9031. + running_injections_.push_back(std::move(injection));
  9032. + break;
  9033. + case ScriptInjection::INJECTION_FINISHED:
  9034. + break;
  9035. + }
  9036. +}
  9037. +
  9038. +} // namespace extensions
  9039. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  9040. new file mode 100755
  9041. --- /dev/null
  9042. +++ b/components/user_scripts/renderer/script_injection_manager.h
  9043. @@ -0,0 +1,101 @@
  9044. +#include <stdint.h>
  9045. +
  9046. +#include <map>
  9047. +#include <set>
  9048. +#include <string>
  9049. +#include <vector>
  9050. +
  9051. +#include "base/callback.h"
  9052. +#include "base/scoped_observation.h"
  9053. +#include "../common/user_script.h"
  9054. +#include "script_injection.h"
  9055. +#include "user_script_set_manager.h"
  9056. +
  9057. +namespace user_scripts {
  9058. +
  9059. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  9060. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  9061. +// maintaining any pending injections awaiting permission or the appropriate
  9062. +// load point, and injecting them when ready.
  9063. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  9064. + public:
  9065. + ScriptInjectionManager(const ScriptInjectionManager&) = delete;
  9066. + ScriptInjectionManager& operator=(const ScriptInjectionManager&) = delete;
  9067. + explicit ScriptInjectionManager(
  9068. + UserScriptSetManager* user_script_set_manager);
  9069. + virtual ~ScriptInjectionManager();
  9070. +
  9071. + // Notifies that a new render view has been created.
  9072. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  9073. +
  9074. + // Removes pending injections of the unloaded extension.
  9075. + //void OnExtensionUnloaded(const std::string& extension_id);
  9076. +
  9077. + void set_activity_logging_enabled(bool enabled) {
  9078. + activity_logging_enabled_ = enabled;
  9079. + }
  9080. +
  9081. + private:
  9082. + // A RenderFrameObserver implementation which watches the various render
  9083. + // frames in order to notify the ScriptInjectionManager of different
  9084. + // document load states and IPCs.
  9085. + class RFOHelper;
  9086. +
  9087. + using FrameStatusMap =
  9088. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  9089. +
  9090. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  9091. +
  9092. + // Notifies that an injection has been finished.
  9093. + void OnInjectionFinished(ScriptInjection* injection);
  9094. +
  9095. + // UserScriptSetManager::Observer implementation.
  9096. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  9097. +
  9098. + // Notifies that an RFOHelper should be removed.
  9099. + void RemoveObserver(RFOHelper* helper);
  9100. +
  9101. + // Invalidate any pending tasks associated with |frame|.
  9102. + void InvalidateForFrame(content::RenderFrame* frame);
  9103. +
  9104. + // Starts the process to inject appropriate scripts into |frame|.
  9105. + void StartInjectScripts(content::RenderFrame* frame,
  9106. + UserScript::RunLocation run_location);
  9107. +
  9108. + // Actually injects the scripts into |frame|.
  9109. + void InjectScripts(content::RenderFrame* frame,
  9110. + UserScript::RunLocation run_location);
  9111. +
  9112. + // Try to inject and store injection if it has not finished.
  9113. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  9114. + UserScript::RunLocation run_location,
  9115. + ScriptsRunInfo* scripts_run_info);
  9116. +
  9117. + // The map of active web frames to their corresponding statuses. The
  9118. + // RunLocation of the frame corresponds to the last location that has ran.
  9119. + FrameStatusMap frame_statuses_;
  9120. +
  9121. + // The frames currently being injected into, so long as that frame is valid.
  9122. + std::set<content::RenderFrame*> active_injection_frames_;
  9123. +
  9124. + // The collection of RFOHelpers.
  9125. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  9126. +
  9127. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  9128. + UserScriptSetManager* user_script_set_manager_;
  9129. +
  9130. + // Pending injections which are waiting for either the proper run location or
  9131. + // user consent.
  9132. + ScriptInjectionVector pending_injections_;
  9133. +
  9134. + // Running injections which are waiting for async callbacks from blink.
  9135. + ScriptInjectionVector running_injections_;
  9136. +
  9137. + // Whether or not dom activity should be logged for scripts injected.
  9138. + bool activity_logging_enabled_ = false;
  9139. +
  9140. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  9141. + user_script_set_manager_observation_{this};
  9142. +};
  9143. +
  9144. +}
  9145. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  9146. new file mode 100755
  9147. --- /dev/null
  9148. +++ b/components/user_scripts/renderer/script_injector.h
  9149. @@ -0,0 +1,96 @@
  9150. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9151. +// Use of this source code is governed by a BSD-style license that can be
  9152. +// found in the LICENSE file.
  9153. +
  9154. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9155. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9156. +
  9157. +#include <memory>
  9158. +#include <vector>
  9159. +
  9160. +#include "../common/constants.h"
  9161. +#include "../common/user_script.h"
  9162. +#include "third_party/blink/public/web/web_script_source.h"
  9163. +
  9164. +class InjectionHost;
  9165. +
  9166. +namespace blink {
  9167. +class WebLocalFrame;
  9168. +}
  9169. +
  9170. +namespace user_scripts {
  9171. +
  9172. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  9173. +// information about how to inject the script, including what code to inject and
  9174. +// when (run location), but without any injection logic.
  9175. +class ScriptInjector {
  9176. + public:
  9177. + // The possible reasons for not injecting the script.
  9178. + enum InjectFailureReason {
  9179. + EXTENSION_REMOVED, // The extension was removed before injection.
  9180. + NOT_ALLOWED, // The script is not allowed to inject.
  9181. + WONT_INJECT // The injection won't inject because the user rejected
  9182. + // (or just did not accept) the injection.
  9183. + };
  9184. +
  9185. + virtual ~ScriptInjector() {}
  9186. +
  9187. + // Returns the script type of this particular injection.
  9188. + virtual UserScript::InjectionType script_type() const = 0;
  9189. +
  9190. + // Returns true if the script is running inside a user gesture.
  9191. + virtual bool IsUserGesture() const = 0;
  9192. +
  9193. + // Returns the CSS origin of this injection.
  9194. + virtual absl::optional<CSSOrigin> GetCssOrigin() const = 0;
  9195. +
  9196. + // Returns the key for this injection, if it's a CSS injection.
  9197. + virtual const absl::optional<std::string> GetInjectionKey() const = 0;
  9198. +
  9199. + // Returns true if the script expects results.
  9200. + virtual bool ExpectsResults() const = 0;
  9201. +
  9202. + // Returns true if the script should inject JS source at the given
  9203. + // |run_location|.
  9204. + virtual bool ShouldInjectJs(
  9205. + UserScript::RunLocation run_location,
  9206. + const std::set<std::string>& executing_scripts) const = 0;
  9207. +
  9208. + // Returns true if the script should inject CSS at the given |run_location|.
  9209. + virtual bool ShouldInjectCss(
  9210. + UserScript::RunLocation run_location,
  9211. + const std::set<std::string>& injected_stylesheets) const = 0;
  9212. +
  9213. + // Returns the javascript sources to inject at the given |run_location|.
  9214. + // Only called if ShouldInjectJs() is true.
  9215. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  9216. + UserScript::RunLocation run_location,
  9217. + std::set<std::string>* executing_scripts,
  9218. + size_t* num_injected_js_scripts) const = 0;
  9219. +
  9220. + // Returns the css to inject at the given |run_location|.
  9221. + // Only called if ShouldInjectCss() is true.
  9222. + virtual std::vector<blink::WebString> GetCssSources(
  9223. + UserScript::RunLocation run_location,
  9224. + std::set<std::string>* injected_stylesheets,
  9225. + size_t* num_injected_stylesheets) const = 0;
  9226. +
  9227. + // Notifies the script that injection has completed, with a possibly-populated
  9228. + // list of results (depending on whether or not ExpectsResults() was true).
  9229. + // |render_frame| contains the render frame, or null if the frame was
  9230. + // invalidated.
  9231. + virtual void OnInjectionComplete(
  9232. + std::unique_ptr<base::Value> execution_result,
  9233. + UserScript::RunLocation run_location,
  9234. + content::RenderFrame* render_frame) = 0;
  9235. +
  9236. + // Notifies the script that injection will never occur.
  9237. + // |render_frame| contains the render frame, or null if the frame was
  9238. + // invalidated.
  9239. + virtual void OnWillNotInject(InjectFailureReason reason,
  9240. + content::RenderFrame* render_frame) = 0;
  9241. +};
  9242. +
  9243. +} // namespace extensions
  9244. +
  9245. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9246. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  9247. new file mode 100755
  9248. --- /dev/null
  9249. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  9250. @@ -0,0 +1,31 @@
  9251. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9252. +// Use of this source code is governed by a BSD-style license that can be
  9253. +// found in the LICENSE file.
  9254. +
  9255. +#include "scripts_run_info.h"
  9256. +
  9257. +#include "base/metrics/histogram_macros.h"
  9258. +#include "content/public/renderer/render_frame.h"
  9259. +#include "content/public/renderer/render_thread.h"
  9260. +#include "script_context.h"
  9261. +#include "third_party/blink/public/web/web_local_frame.h"
  9262. +
  9263. +namespace user_scripts {
  9264. +
  9265. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  9266. + UserScript::RunLocation location)
  9267. + : num_css(0u),
  9268. + num_js(0u),
  9269. + num_blocking_js(0u),
  9270. + routing_id_(render_frame->GetRoutingID()),
  9271. + run_location_(location),
  9272. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  9273. + render_frame->GetWebFrame())) {}
  9274. +
  9275. +ScriptsRunInfo::~ScriptsRunInfo() {
  9276. +}
  9277. +
  9278. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  9279. +}
  9280. +
  9281. +} // namespace extensions
  9282. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  9283. new file mode 100755
  9284. --- /dev/null
  9285. +++ b/components/user_scripts/renderer/scripts_run_info.h
  9286. @@ -0,0 +1,69 @@
  9287. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9288. +// Use of this source code is governed by a BSD-style license that can be
  9289. +// found in the LICENSE file.
  9290. +
  9291. +#ifndef USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9292. +#define USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9293. +
  9294. +#include <stddef.h>
  9295. +
  9296. +#include <map>
  9297. +#include <set>
  9298. +#include <string>
  9299. +
  9300. +#include "base/timer/elapsed_timer.h"
  9301. +#include "../common/user_script.h"
  9302. +
  9303. +namespace content {
  9304. +class RenderFrame;
  9305. +}
  9306. +
  9307. +namespace user_scripts {
  9308. +
  9309. +// A struct containing information about a script run.
  9310. +struct ScriptsRunInfo {
  9311. + ScriptsRunInfo(const ScriptsRunInfo&) = delete;
  9312. + ScriptsRunInfo& operator=(const ScriptsRunInfo&) = delete;
  9313. + // Map of extensions IDs to the executing script paths.
  9314. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  9315. +
  9316. + ScriptsRunInfo(content::RenderFrame* render_frame,
  9317. + UserScript::RunLocation location);
  9318. + ~ScriptsRunInfo();
  9319. +
  9320. + // The number of CSS scripts injected.
  9321. + size_t num_css;
  9322. + // The number of JS scripts injected.
  9323. + size_t num_js;
  9324. + // The number of blocked JS scripts injected.
  9325. + size_t num_blocking_js;
  9326. + // A map of extension ids to executing script paths.
  9327. + ExecutingScriptsMap executing_scripts;
  9328. + // A map of extension ids to injected stylesheet paths.
  9329. + ExecutingScriptsMap injected_stylesheets;
  9330. + // The elapsed time since the ScriptsRunInfo was constructed.
  9331. + base::ElapsedTimer timer;
  9332. +
  9333. + // Log information about a given script run. If |send_script_activity| is
  9334. + // true, this also informs the browser of the script run.
  9335. + void LogRun(bool send_script_activity);
  9336. +
  9337. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  9338. + const base::TimeDelta& elapsed);
  9339. +
  9340. + private:
  9341. + // The routinig id to use to notify the browser of any injections. Since the
  9342. + // frame may be deleted in injection, we don't hold on to a reference to it
  9343. + // directly.
  9344. + int routing_id_;
  9345. +
  9346. + // The run location at which injection is happening.
  9347. + UserScript::RunLocation run_location_;
  9348. +
  9349. + // The url of the frame, preserved for the same reason as the routing id.
  9350. + GURL frame_url_;
  9351. +};
  9352. +
  9353. +} // namespace extensions
  9354. +
  9355. +#endif // USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9356. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  9357. new file mode 100755
  9358. --- /dev/null
  9359. +++ b/components/user_scripts/renderer/user_script_injector.cc
  9360. @@ -0,0 +1,228 @@
  9361. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9362. +// Use of this source code is governed by a BSD-style license that can be
  9363. +// found in the LICENSE file.
  9364. +
  9365. +#include "user_script_injector.h"
  9366. +
  9367. +#include <tuple>
  9368. +#include <vector>
  9369. +
  9370. +#include "base/logging.h"
  9371. +#include "base/lazy_instance.h"
  9372. +#include "content/public/common/url_constants.h"
  9373. +#include "content/public/renderer/render_frame.h"
  9374. +#include "content/public/renderer/render_thread.h"
  9375. +#include "content/public/renderer/render_view.h"
  9376. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  9377. +#include "injection_host.h"
  9378. +#include "script_context.h"
  9379. +#include "scripts_run_info.h"
  9380. +#include "third_party/blink/public/web/web_document.h"
  9381. +#include "third_party/blink/public/web/web_local_frame.h"
  9382. +#include "third_party/blink/public/web/web_script_source.h"
  9383. +#include "ui/base/resource/resource_bundle.h"
  9384. +#include "url/gurl.h"
  9385. +
  9386. +namespace user_scripts {
  9387. +
  9388. +namespace {
  9389. +
  9390. +struct RoutingInfoKey {
  9391. + int routing_id;
  9392. + int script_id;
  9393. +
  9394. + RoutingInfoKey(int routing_id, int script_id)
  9395. + : routing_id(routing_id), script_id(script_id) {}
  9396. +
  9397. + bool operator<(const RoutingInfoKey& other) const {
  9398. + return std::tie(routing_id, script_id) <
  9399. + std::tie(other.routing_id, other.script_id);
  9400. + }
  9401. +};
  9402. +
  9403. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  9404. +
  9405. +// A map records whether a given |script_id| from a webview-added user script
  9406. +// is allowed to inject on the render of given |routing_id|.
  9407. +// Once a script is added, the decision of whether or not allowed to inject
  9408. +// won't be changed.
  9409. +// After removed by the webview, the user scipt will also be removed
  9410. +// from the render. Therefore, there won't be any query from the same
  9411. +// |script_id| and |routing_id| pair.
  9412. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  9413. +// LAZY_INSTANCE_INITIALIZER;
  9414. +
  9415. +// Greasemonkey API source that is injected with the scripts.
  9416. +struct GreasemonkeyApiJsString {
  9417. + GreasemonkeyApiJsString();
  9418. + blink::WebScriptSource GetSource() const;
  9419. +
  9420. + private:
  9421. + blink::WebString source_;
  9422. +};
  9423. +
  9424. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  9425. +// the GreasemonkeyApiJs resource.
  9426. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  9427. + std::string greasemonky_api_js(
  9428. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  9429. + IDR_GREASEMONKEY_API_JS));
  9430. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  9431. +}
  9432. +
  9433. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  9434. + return blink::WebScriptSource(source_);
  9435. +}
  9436. +
  9437. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  9438. + LAZY_INSTANCE_INITIALIZER;
  9439. +
  9440. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  9441. + const std::set<std::string>& injected_files) {
  9442. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  9443. + // Check if the script is already injected.
  9444. + if (injected_files.count(file->url().path()) == 0) {
  9445. + return true;
  9446. + }
  9447. + }
  9448. + return false;
  9449. +}
  9450. +
  9451. +} // namespace
  9452. +
  9453. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  9454. + UserScriptSet* script_list)
  9455. + : script_(script),
  9456. + user_script_set_(script_list),
  9457. + script_id_(script_->id()),
  9458. + user_script_set_observer_(this) {
  9459. + user_script_set_observer_.Observe(script_list);
  9460. +}
  9461. +
  9462. +UserScriptInjector::~UserScriptInjector() {
  9463. +}
  9464. +
  9465. +void UserScriptInjector::OnUserScriptsUpdated(
  9466. + const std::set<HostID>& changed_hosts,
  9467. + const UserScriptList& scripts) {
  9468. + // When user scripts are updated, all the old script pointers are invalidated.
  9469. + script_ = nullptr;
  9470. + // If the host causing this injection changed, then this injection
  9471. + // will be removed, and there's no guarantee the backing script still exists.
  9472. + // if (changed_hosts.count(host_id_) > 0)
  9473. + // return;
  9474. +
  9475. + for (const std::unique_ptr<UserScript>& script : scripts) {
  9476. + if (script->id() == script_id_) {
  9477. + script_ = script.get();
  9478. + break;
  9479. + }
  9480. + }
  9481. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  9482. + // should be guaranteed to exist.
  9483. + DCHECK(script_);
  9484. +}
  9485. +
  9486. +UserScript::InjectionType UserScriptInjector::script_type() const {
  9487. + return UserScript::CONTENT_SCRIPT;
  9488. +}
  9489. +
  9490. +bool UserScriptInjector::IsUserGesture() const {
  9491. + return false;
  9492. +}
  9493. +
  9494. +bool UserScriptInjector::ExpectsResults() const {
  9495. + return false;
  9496. +}
  9497. +
  9498. +absl::optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  9499. + return absl::nullopt;
  9500. +}
  9501. +
  9502. +const absl::optional<std::string> UserScriptInjector::GetInjectionKey() const {
  9503. + return absl::nullopt;
  9504. +}
  9505. +
  9506. +bool UserScriptInjector::ShouldInjectJs(
  9507. + UserScript::RunLocation run_location,
  9508. + const std::set<std::string>& executing_scripts) const {
  9509. + return script_ && script_->run_location() == run_location &&
  9510. + !script_->js_scripts().empty() &&
  9511. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  9512. +}
  9513. +
  9514. +bool UserScriptInjector::ShouldInjectCss(
  9515. + UserScript::RunLocation run_location,
  9516. + const std::set<std::string>& injected_stylesheets) const {
  9517. + return script_ && run_location == UserScript::DOCUMENT_START &&
  9518. + !script_->css_scripts().empty() &&
  9519. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  9520. +}
  9521. +
  9522. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  9523. + UserScript::RunLocation run_location,
  9524. + std::set<std::string>* executing_scripts,
  9525. + size_t* num_injected_js_scripts) const {
  9526. + DCHECK(script_);
  9527. + std::vector<blink::WebScriptSource> sources;
  9528. +
  9529. + DCHECK_EQ(script_->run_location(), run_location);
  9530. +
  9531. + const UserScript::FileList& js_scripts = script_->js_scripts();
  9532. + sources.reserve(js_scripts.size() +
  9533. + (script_->emulate_greasemonkey() ? 1 : 0));
  9534. + // Emulate Greasemonkey API for scripts that were converted to extension
  9535. + // user scripts.
  9536. + if (script_->emulate_greasemonkey())
  9537. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  9538. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  9539. + const GURL& script_url = file->url();
  9540. + // Check if the script is already injected.
  9541. + if (executing_scripts->count(script_url.path()) != 0)
  9542. + continue;
  9543. +
  9544. + sources.push_back(blink::WebScriptSource(
  9545. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  9546. + script_url));
  9547. +
  9548. + (*num_injected_js_scripts) += 1;
  9549. + executing_scripts->insert(script_url.path());
  9550. + }
  9551. +
  9552. + return sources;
  9553. +}
  9554. +
  9555. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  9556. + UserScript::RunLocation run_location,
  9557. + std::set<std::string>* injected_stylesheets,
  9558. + size_t* num_injected_stylesheets) const {
  9559. + DCHECK(script_);
  9560. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  9561. +
  9562. + std::vector<blink::WebString> sources;
  9563. +
  9564. + const UserScript::FileList& css_scripts = script_->css_scripts();
  9565. + sources.reserve(css_scripts.size());
  9566. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  9567. + const std::string& stylesheet_path = file->url().path();
  9568. + // Check if the stylesheet is already injected.
  9569. + if (injected_stylesheets->count(stylesheet_path) != 0)
  9570. + continue;
  9571. +
  9572. + sources.push_back(user_script_set_->GetCssSource(*file));
  9573. + (*num_injected_stylesheets) += 1;
  9574. + injected_stylesheets->insert(stylesheet_path);
  9575. + }
  9576. + return sources;
  9577. +}
  9578. +
  9579. +void UserScriptInjector::OnInjectionComplete(
  9580. + std::unique_ptr<base::Value> execution_result,
  9581. + UserScript::RunLocation run_location,
  9582. + content::RenderFrame* render_frame) {}
  9583. +
  9584. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  9585. + content::RenderFrame* render_frame) {
  9586. +}
  9587. +
  9588. +} // namespace extensions
  9589. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  9590. new file mode 100755
  9591. --- /dev/null
  9592. +++ b/components/user_scripts/renderer/user_script_injector.h
  9593. @@ -0,0 +1,86 @@
  9594. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9595. +// Use of this source code is governed by a BSD-style license that can be
  9596. +// found in the LICENSE file.
  9597. +
  9598. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9599. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9600. +
  9601. +#include <memory>
  9602. +#include <string>
  9603. +
  9604. +#include "base/values.h"
  9605. +#include "base/scoped_observation.h"
  9606. +#include "../common/user_script.h"
  9607. +#include "script_injection.h"
  9608. +#include "user_script_set.h"
  9609. +
  9610. +class InjectionHost;
  9611. +
  9612. +namespace blink {
  9613. +class WebLocalFrame;
  9614. +}
  9615. +
  9616. +namespace user_scripts {
  9617. +
  9618. +// A ScriptInjector for UserScripts.
  9619. +class UserScriptInjector : public ScriptInjector,
  9620. + public UserScriptSet::Observer {
  9621. + public:
  9622. + UserScriptInjector(const UserScriptInjector&) = delete;
  9623. + UserScriptInjector& operator=(const UserScriptInjector&) = delete;
  9624. + UserScriptInjector(const UserScript* user_script,
  9625. + UserScriptSet* user_script_set);
  9626. + ~UserScriptInjector() override;
  9627. +
  9628. + private:
  9629. + // UserScriptSet::Observer implementation.
  9630. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9631. + const UserScriptList& scripts) override;
  9632. +
  9633. + // ScriptInjector implementation.
  9634. + UserScript::InjectionType script_type() const override;
  9635. + bool IsUserGesture() const override;
  9636. + absl::optional<CSSOrigin> GetCssOrigin() const override;
  9637. + const absl::optional<std::string> GetInjectionKey() const override;
  9638. + bool ExpectsResults() const override;
  9639. + bool ShouldInjectJs(
  9640. + UserScript::RunLocation run_location,
  9641. + const std::set<std::string>& executing_scripts) const override;
  9642. + bool ShouldInjectCss(
  9643. + UserScript::RunLocation run_location,
  9644. + const std::set<std::string>& injected_stylesheets) const override;
  9645. + std::vector<blink::WebScriptSource> GetJsSources(
  9646. + UserScript::RunLocation run_location,
  9647. + std::set<std::string>* executing_scripts,
  9648. + size_t* num_injected_js_scripts) const override;
  9649. + std::vector<blink::WebString> GetCssSources(
  9650. + UserScript::RunLocation run_location,
  9651. + std::set<std::string>* injected_stylesheets,
  9652. + size_t* num_injected_stylesheets) const override;
  9653. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  9654. + UserScript::RunLocation run_location,
  9655. + content::RenderFrame* render_frame) override;
  9656. + void OnWillNotInject(InjectFailureReason reason,
  9657. + content::RenderFrame* render_frame) override;
  9658. +
  9659. + // The associated user script. Owned by the UserScriptInjector that created
  9660. + // this object.
  9661. + const UserScript* script_;
  9662. +
  9663. + // The UserScriptSet that eventually owns the UserScript this
  9664. + // UserScriptInjector points to.
  9665. + // Outlives |this|.
  9666. + UserScriptSet* const user_script_set_;
  9667. +
  9668. + // The id of the associated user script. We cache this because when we update
  9669. + // the |script_| associated with this injection, the old referance may be
  9670. + // deleted.
  9671. + int script_id_;
  9672. +
  9673. + base::ScopedObservation<UserScriptSet, UserScriptSet::Observer>
  9674. + user_script_set_observer_{this};
  9675. +};
  9676. +
  9677. +} // namespace extensions
  9678. +
  9679. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9680. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  9681. new file mode 100755
  9682. --- /dev/null
  9683. +++ b/components/user_scripts/renderer/user_script_set.cc
  9684. @@ -0,0 +1,262 @@
  9685. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9686. +// Use of this source code is governed by a BSD-style license that can be
  9687. +// found in the LICENSE file.
  9688. +
  9689. +#include "user_script_set.h"
  9690. +
  9691. +#include <stddef.h>
  9692. +
  9693. +#include <utility>
  9694. +
  9695. +#include "base/logging.h"
  9696. +#include "base/debug/alias.h"
  9697. +#include "base/memory/ref_counted.h"
  9698. +#include "base/strings/strcat.h"
  9699. +#include "content/public/common/url_constants.h"
  9700. +#include "content/public/renderer/render_frame.h"
  9701. +#include "content/public/renderer/render_thread.h"
  9702. +#include "injection_host.h"
  9703. +#include "script_context.h"
  9704. +#include "script_injection.h"
  9705. +#include "user_script_injector.h"
  9706. +#include "web_ui_injection_host.h"
  9707. +#include "third_party/blink/public/web/web_document.h"
  9708. +#include "third_party/blink/public/web/web_local_frame.h"
  9709. +#include "url/gurl.h"
  9710. +#include "../common/user_scripts_features.h"
  9711. +
  9712. +namespace user_scripts {
  9713. +
  9714. +namespace {
  9715. +
  9716. +// These two strings are injected before and after the Greasemonkey API and
  9717. +// user script to wrap it in an anonymous scope.
  9718. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  9719. +const char kUserScriptTail[] = "\n})(window);";
  9720. +// Maximum number of total content scripts we allow (across all extensions).
  9721. +// The limit exists to diagnose https://crbug.com/723381. The number is
  9722. +// arbitrarily chosen.
  9723. +// TODO(lazyboy): Remove when the bug is fixed.
  9724. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  9725. +
  9726. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  9727. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  9728. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  9729. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  9730. + data_source_url.spec());
  9731. + }
  9732. +
  9733. + return data_source_url;
  9734. +}
  9735. +
  9736. +} // namespace
  9737. +
  9738. +UserScriptSet::UserScriptSet() {}
  9739. +
  9740. +UserScriptSet::~UserScriptSet() {
  9741. +}
  9742. +
  9743. +void UserScriptSet::AddObserver(Observer* observer) {
  9744. + observers_.AddObserver(observer);
  9745. +}
  9746. +
  9747. +void UserScriptSet::RemoveObserver(Observer* observer) {
  9748. + observers_.RemoveObserver(observer);
  9749. +}
  9750. +
  9751. +void UserScriptSet::GetInjections(
  9752. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9753. + content::RenderFrame* render_frame,
  9754. + int tab_id,
  9755. + UserScript::RunLocation run_location,
  9756. + bool log_activity) {
  9757. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  9758. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  9759. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  9760. + script.get(), render_frame, tab_id, run_location, document_url,
  9761. + /* is_declarative, */ log_activity);
  9762. + if (injection.get())
  9763. + injections->push_back(std::move(injection));
  9764. + }
  9765. +}
  9766. +
  9767. +bool UserScriptSet::UpdateUserScripts(
  9768. + base::ReadOnlySharedMemoryRegion shared_memory,
  9769. + const std::set<HostID>& changed_hosts,
  9770. + bool whitelisted_only) {
  9771. + bool only_inject_incognito = false;
  9772. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  9773. +
  9774. + // Create the shared memory mapping.
  9775. + shared_memory_mapping_ = shared_memory.Map();
  9776. + if (!shared_memory.IsValid())
  9777. + return false;
  9778. +
  9779. + // First get the size of the memory block.
  9780. + const base::Pickle::Header* pickle_header =
  9781. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  9782. + if (!pickle_header)
  9783. + return false;
  9784. +
  9785. + // Now read in the rest of the block.
  9786. + size_t pickle_size =
  9787. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  9788. +
  9789. + // Unpickle scripts.
  9790. + uint32_t num_scripts = 0;
  9791. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9792. + if (!memory.size())
  9793. + return false;
  9794. +
  9795. + base::Pickle pickle(memory.data(), pickle_size);
  9796. + base::PickleIterator iter(pickle);
  9797. + base::debug::Alias(&pickle_size);
  9798. + CHECK(iter.ReadUInt32(&num_scripts));
  9799. +
  9800. + // Sometimes the shared memory contents seem to be corrupted
  9801. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9802. + // scripts so that we don't add OOM noise to crash reports.
  9803. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9804. +
  9805. + scripts_.clear();
  9806. + script_sources_.clear();
  9807. + scripts_.reserve(num_scripts);
  9808. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9809. + std::unique_ptr<UserScript> script(new UserScript());
  9810. + script->Unpickle(pickle, &iter);
  9811. +
  9812. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9813. + // cleared up when the last renderer or browser process drops their
  9814. + // reference to the shared memory.
  9815. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9816. + const char* body = NULL;
  9817. + int body_length = 0;
  9818. + CHECK(iter.ReadData(&body, &body_length));
  9819. + script->js_scripts()[j]->set_external_content(
  9820. + base::StringPiece(body, body_length));
  9821. + }
  9822. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9823. + const char* body = NULL;
  9824. + int body_length = 0;
  9825. + CHECK(iter.ReadData(&body, &body_length));
  9826. + script->css_scripts()[j]->set_external_content(
  9827. + base::StringPiece(body, body_length));
  9828. + }
  9829. +
  9830. + if (only_inject_incognito && !script->is_incognito_enabled())
  9831. + continue; // This script shouldn't run in an incognito tab.
  9832. +
  9833. + scripts_.push_back(std::move(script));
  9834. + }
  9835. +
  9836. + for (auto& observer : observers_)
  9837. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9838. + return true;
  9839. +}
  9840. +
  9841. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9842. + scripts_.push_back(std::move(script));
  9843. +}
  9844. +
  9845. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9846. + const UserScript* script,
  9847. + content::RenderFrame* render_frame,
  9848. + int tab_id,
  9849. + UserScript::RunLocation run_location,
  9850. + const GURL& document_url,
  9851. + //bool is_declarative,
  9852. + bool log_activity) {
  9853. + std::unique_ptr<ScriptInjection> injection;
  9854. + std::unique_ptr<const InjectionHost> injection_host;
  9855. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9856. +
  9857. + const HostID& host_id = script->host_id();
  9858. + injection_host.reset(new WebUIInjectionHost(host_id));
  9859. +
  9860. + GURL effective_document_url =
  9861. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9862. + web_frame, document_url, script->match_origin_as_fallback());
  9863. +
  9864. + bool is_subframe = web_frame->Parent();
  9865. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9866. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9867. + LOG(INFO) << "UserScripts: No Match name=" << script->name() <<
  9868. + " id=" << script->host_id().id() <<
  9869. + " url=" << effective_document_url.spec();
  9870. + return injection;
  9871. + }
  9872. +
  9873. + std::unique_ptr<ScriptInjector> injector(
  9874. + new UserScriptInjector(script, this));
  9875. +
  9876. + bool inject_css = !script->css_scripts().empty() &&
  9877. + run_location == UserScript::DOCUMENT_START;
  9878. + bool inject_js =
  9879. + !script->js_scripts().empty() && script->run_location() == run_location;
  9880. + if (inject_css || inject_js) {
  9881. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9882. + std::move(injection_host), run_location,
  9883. + log_activity));
  9884. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9885. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9886. + "url=" << effective_document_url.spec();
  9887. + } else {
  9888. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9889. + if (script->run_location() != run_location)
  9890. + LOG(INFO) << "UserScripts: run location for name=" << script->name() <<
  9891. + " id=" << script->host_id().id() <<
  9892. + " current " << run_location <<
  9893. + " need " << script->run_location();
  9894. + else
  9895. + LOG(INFO) << "UserScripts: Match but no run name=" << script->name() <<
  9896. + " id=" << script->host_id().id() <<
  9897. + " url=" << effective_document_url.spec();
  9898. + }
  9899. + }
  9900. + return injection;
  9901. +}
  9902. +
  9903. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9904. + bool emulate_greasemonkey) {
  9905. + const GURL& url = file.url();
  9906. + auto iter = script_sources_.find(url);
  9907. + if (iter != script_sources_.end()) {
  9908. + return iter->second;
  9909. + }
  9910. +
  9911. + base::StringPiece script_content = file.GetContent();
  9912. + blink::WebString source;
  9913. + if (emulate_greasemonkey) {
  9914. + // We add this dumb function wrapper for user scripts to emulate what
  9915. + // Greasemonkey does. |script_content| becomes:
  9916. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9917. + std::string content =
  9918. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9919. + source = blink::WebString::FromUTF8(content);
  9920. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9921. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9922. + } else {
  9923. + source = blink::WebString::FromUTF8(script_content.data(),
  9924. + script_content.length());
  9925. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9926. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9927. + }
  9928. + script_sources_[url] = source;
  9929. + return source;
  9930. +}
  9931. +
  9932. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9933. + const GURL& url = file.url();
  9934. + auto iter = script_sources_.find(url);
  9935. + if (iter != script_sources_.end())
  9936. + return iter->second;
  9937. +
  9938. + base::StringPiece script_content = file.GetContent();
  9939. + return script_sources_
  9940. + .insert(std::make_pair(
  9941. + url, blink::WebString::FromUTF8(script_content.data(),
  9942. + script_content.length())))
  9943. + .first->second;
  9944. +}
  9945. +
  9946. +} // namespace extensions
  9947. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9948. new file mode 100755
  9949. --- /dev/null
  9950. +++ b/components/user_scripts/renderer/user_script_set.h
  9951. @@ -0,0 +1,101 @@
  9952. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9953. +// Use of this source code is governed by a BSD-style license that can be
  9954. +// found in the LICENSE file.
  9955. +
  9956. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9957. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9958. +
  9959. +#include <map>
  9960. +#include <memory>
  9961. +#include <set>
  9962. +#include <string>
  9963. +#include <vector>
  9964. +
  9965. +#include "base/memory/read_only_shared_memory_region.h"
  9966. +#include "base/observer_list.h"
  9967. +#include "../common/user_script.h"
  9968. +#include "third_party/blink/public/platform/web_string.h"
  9969. +
  9970. +class GURL;
  9971. +
  9972. +namespace content {
  9973. +class RenderFrame;
  9974. +}
  9975. +
  9976. +namespace user_scripts {
  9977. +class ScriptInjection;
  9978. +
  9979. +// The UserScriptSet is a collection of UserScripts which knows how to update
  9980. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  9981. +// inject on a page.
  9982. +class UserScriptSet {
  9983. + public:
  9984. + UserScriptSet(const UserScriptSet&) = delete;
  9985. + UserScriptSet& operator=(const UserScriptSet&) = delete;
  9986. + class Observer {
  9987. + public:
  9988. + // Called when the set of user scripts is updated. |changed_hosts| contains
  9989. + // the hosts whose scripts have been altered. Note that *all* script objects
  9990. + // are invalidated, even if they aren't in |changed_hosts|.
  9991. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9992. + const UserScriptList& scripts) = 0;
  9993. + };
  9994. +
  9995. + UserScriptSet();
  9996. + ~UserScriptSet();
  9997. +
  9998. + // Adds or removes observers.
  9999. + void AddObserver(Observer* observer);
  10000. + void RemoveObserver(Observer* observer);
  10001. + void AddScript(std::unique_ptr<UserScript> script);
  10002. +
  10003. + // Append any ScriptInjections that should run on the given |render_frame| and
  10004. + // |tab_id|, at the given |run_location|, to |injections|.
  10005. + // |extensions| is passed in to verify the corresponding extension is still
  10006. + // valid.
  10007. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10008. + content::RenderFrame* render_frame,
  10009. + int tab_id,
  10010. + UserScript::RunLocation run_location,
  10011. + bool log_activity);
  10012. +
  10013. + // Updates scripts given the shared memory region containing user scripts.
  10014. + // Returns true if the scripts were successfully updated.
  10015. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  10016. + const std::set<HostID>& changed_hosts,
  10017. + bool whitelisted_only);
  10018. +
  10019. + // Returns the contents of a script file.
  10020. + // Note that copying is cheap as this uses WebString.
  10021. + blink::WebString GetJsSource(const UserScript::File& file,
  10022. + bool emulate_greasemonkey);
  10023. + blink::WebString GetCssSource(const UserScript::File& file);
  10024. +
  10025. + private:
  10026. + // Returns a new ScriptInjection for the given |script| to execute in the
  10027. + // |render_frame|, or NULL if the script should not execute.
  10028. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  10029. + const UserScript* script,
  10030. + content::RenderFrame* render_frame,
  10031. + int tab_id,
  10032. + UserScript::RunLocation run_location,
  10033. + const GURL& document_url,
  10034. + //bool is_declarative,
  10035. + bool log_activity);
  10036. +
  10037. + // Shared memory mapping containing raw script data.
  10038. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  10039. +
  10040. + // The UserScripts this injector manages.
  10041. + UserScriptList scripts_;
  10042. +
  10043. + // Map of user script file url -> source.
  10044. + std::map<GURL, blink::WebString> script_sources_;
  10045. +
  10046. + // The associated observers.
  10047. + base::ObserverList<Observer>::Unchecked observers_;
  10048. +};
  10049. +
  10050. +} // namespace extensions
  10051. +
  10052. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  10053. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  10054. new file mode 100755
  10055. --- /dev/null
  10056. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  10057. @@ -0,0 +1,77 @@
  10058. +#include "user_script_set_manager.h"
  10059. +
  10060. +#include "base/logging.h"
  10061. +#include "content/public/renderer/render_thread.h"
  10062. +#include "../common/host_id.h"
  10063. +#include "../common/extension_messages.h"
  10064. +#include "../common/user_scripts_features.h"
  10065. +#include "user_script_set.h"
  10066. +
  10067. +namespace user_scripts {
  10068. +
  10069. +UserScriptSetManager::UserScriptSetManager() {
  10070. + content::RenderThread::Get()->AddObserver(this);
  10071. +}
  10072. +
  10073. +UserScriptSetManager::~UserScriptSetManager() {
  10074. +}
  10075. +
  10076. +void UserScriptSetManager::AddObserver(Observer* observer) {
  10077. + observers_.AddObserver(observer);
  10078. +}
  10079. +
  10080. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  10081. + observers_.RemoveObserver(observer);
  10082. +}
  10083. +
  10084. +bool UserScriptSetManager::OnControlMessageReceived(
  10085. + const IPC::Message& message) {
  10086. + bool handled = true;
  10087. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  10088. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  10089. + IPC_MESSAGE_UNHANDLED(handled = false)
  10090. + IPC_END_MESSAGE_MAP()
  10091. + return handled;
  10092. +}
  10093. +
  10094. +void UserScriptSetManager::GetAllInjections(
  10095. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10096. + content::RenderFrame* render_frame,
  10097. + int tab_id,
  10098. + UserScript::RunLocation run_location) {
  10099. +
  10100. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10101. + LOG(INFO) << "UserScripts: GetAllInjections";
  10102. +
  10103. + // static_scripts_ is UserScriptSet
  10104. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  10105. + activity_logging_enabled_);
  10106. +}
  10107. +
  10108. +void UserScriptSetManager::OnUpdateUserScripts(
  10109. + base::ReadOnlySharedMemoryRegion shared_memory) {
  10110. + if (!shared_memory.IsValid()) {
  10111. + NOTREACHED() << "Bad scripts handle";
  10112. + return;
  10113. + }
  10114. +
  10115. + UserScriptSet* scripts = NULL;
  10116. + scripts = &static_scripts_;
  10117. +
  10118. + DCHECK(scripts);
  10119. +
  10120. + // If no hosts are included in the set, that indicates that all
  10121. + // hosts were updated. Add them all to the set so that observers and
  10122. + // individual UserScriptSets don't need to know this detail.
  10123. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  10124. + std::set<HostID> all_hosts;
  10125. + const std::set<HostID>* effective_hosts = &all_hosts;
  10126. +
  10127. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  10128. + false /*whitelisted_only*/)) {
  10129. + for (auto& observer : observers_)
  10130. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  10131. + }
  10132. +}
  10133. +
  10134. +}
  10135. \ No newline at end of file
  10136. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  10137. new file mode 100755
  10138. --- /dev/null
  10139. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  10140. @@ -0,0 +1,61 @@
  10141. +#ifndef USERSCRIPTS_RENDER_SET_MANAGER_H_
  10142. +#define USERSCRIPTS_RENDER_SET_MANAGER_H_
  10143. +
  10144. +#include <map>
  10145. +#include <set>
  10146. +#include <string>
  10147. +#include <vector>
  10148. +
  10149. +#include "base/memory/read_only_shared_memory_region.h"
  10150. +#include "base/observer_list.h"
  10151. +#include "content/public/renderer/render_thread_observer.h"
  10152. +#include "../common/host_id.h"
  10153. +#include "user_script_set.h"
  10154. +#include "script_injection.h"
  10155. +
  10156. +namespace user_scripts {
  10157. +
  10158. +class UserScriptSetManager : public content::RenderThreadObserver {
  10159. + public:
  10160. + class Observer {
  10161. + public:
  10162. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  10163. + };
  10164. +
  10165. + UserScriptSetManager();
  10166. +
  10167. + ~UserScriptSetManager() override;
  10168. +
  10169. + void AddObserver(Observer* observer);
  10170. + void RemoveObserver(Observer* observer);
  10171. +
  10172. + // Append all injections from |static_scripts| and each of
  10173. + // |programmatic_scripts_| to |injections|.
  10174. + void GetAllInjections(
  10175. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10176. + content::RenderFrame* render_frame,
  10177. + int tab_id,
  10178. + UserScript::RunLocation run_location);
  10179. +
  10180. +private:
  10181. + // content::RenderThreadObserver implementation.
  10182. + bool OnControlMessageReceived(const IPC::Message& message) override;
  10183. +
  10184. + base::ObserverList<Observer>::Unchecked observers_;
  10185. +
  10186. + // Handle the UpdateUserScripts extension message.
  10187. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  10188. + //, const HostID& host_id,
  10189. + //const std::set<HostID>& changed_hosts,
  10190. + //bool whitelisted_only);
  10191. +
  10192. + // Scripts statically defined in extension manifests.
  10193. + UserScriptSet static_scripts_;
  10194. +
  10195. + // Whether or not dom activity should be logged for scripts injected.
  10196. + bool activity_logging_enabled_ = false;
  10197. +};
  10198. +
  10199. +}
  10200. +
  10201. +#endif
  10202. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10203. new file mode 100755
  10204. --- /dev/null
  10205. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10206. @@ -0,0 +1,36 @@
  10207. +#include "user_scripts_dispatcher.h"
  10208. +
  10209. +#include <stddef.h>
  10210. +
  10211. +#include <algorithm>
  10212. +#include <memory>
  10213. +#include <utility>
  10214. +
  10215. +#include "content/public/renderer/render_thread.h"
  10216. +#include "extension_frame_helper.h"
  10217. +
  10218. +namespace user_scripts {
  10219. +
  10220. +// ex ChromeExtensionsDispatcherDelegate
  10221. +UserScriptsDispatcher::UserScriptsDispatcher()
  10222. + : user_script_set_manager_observer_(this) {
  10223. + user_script_set_manager_.reset(new UserScriptSetManager());
  10224. + script_injection_manager_.reset(
  10225. + new ScriptInjectionManager(user_script_set_manager_.get()));
  10226. + user_script_set_manager_observer_.Observe(user_script_set_manager_.get());
  10227. +}
  10228. +
  10229. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  10230. +}
  10231. +
  10232. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  10233. +}
  10234. +
  10235. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  10236. +}
  10237. +
  10238. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  10239. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  10240. +}
  10241. +
  10242. +}
  10243. \ No newline at end of file
  10244. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10245. new file mode 100755
  10246. --- /dev/null
  10247. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10248. @@ -0,0 +1,49 @@
  10249. +#ifndef USERSCRIPTS_RENDER_DISPATCHER_H_
  10250. +#define USERSCRIPTS_RENDER_DISPATCHER_H_
  10251. +
  10252. +#include "user_script_set_manager.h"
  10253. +#include "script_injection_manager.h"
  10254. +
  10255. +#include <stdint.h>
  10256. +
  10257. +#include <map>
  10258. +#include <memory>
  10259. +#include <set>
  10260. +#include <string>
  10261. +#include <utility>
  10262. +#include <vector>
  10263. +
  10264. +#include "base/scoped_observation.h"
  10265. +#include "content/public/renderer/render_thread_observer.h"
  10266. +#include "content/public/renderer/render_thread.h"
  10267. +#include "../common/host_id.h"
  10268. +#include "user_script_set_manager.h"
  10269. +#include "script_injection.h"
  10270. +
  10271. +namespace user_scripts {
  10272. +
  10273. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  10274. + public UserScriptSetManager::Observer {
  10275. +
  10276. + public:
  10277. + UserScriptsDispatcher(const UserScriptsDispatcher&) = delete;
  10278. + UserScriptsDispatcher& operator=(const UserScriptsDispatcher&) = delete;
  10279. + explicit UserScriptsDispatcher();
  10280. + ~UserScriptsDispatcher() override;
  10281. +
  10282. + void OnRenderThreadStarted(content::RenderThread* thread);
  10283. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  10284. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  10285. +
  10286. + private:
  10287. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  10288. +
  10289. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  10290. +
  10291. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  10292. + user_script_set_manager_observer_{this};
  10293. +};
  10294. +
  10295. +}
  10296. +
  10297. +#endif
  10298. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10299. new file mode 100755
  10300. --- /dev/null
  10301. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10302. @@ -0,0 +1,105 @@
  10303. +#include "user_scripts_renderer_client.h"
  10304. +
  10305. +#include <memory>
  10306. +#include <utility>
  10307. +
  10308. +#include "base/logging.h"
  10309. +#include "base/lazy_instance.h"
  10310. +#include "content/public/renderer/render_frame.h"
  10311. +#include "content/public/renderer/render_thread.h"
  10312. +#include "content/public/renderer/render_frame_visitor.h"
  10313. +#include "chrome/renderer/chrome_render_thread_observer.h"
  10314. +
  10315. +#include "../common/user_scripts_features.h"
  10316. +#include "user_scripts_dispatcher.h"
  10317. +#include "extension_frame_helper.h"
  10318. +
  10319. +namespace user_scripts {
  10320. +
  10321. +// was ChromeExtensionsRendererClient
  10322. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  10323. +
  10324. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  10325. +
  10326. +// static
  10327. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  10328. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  10329. + LAZY_INSTANCE_INITIALIZER;
  10330. + return client.Pointer();
  10331. +}
  10332. +
  10333. +void UserScriptsRendererClient::RenderThreadStarted() {
  10334. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10335. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  10336. +
  10337. + content::RenderThread* thread = content::RenderThread::Get();
  10338. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  10339. +
  10340. + dispatcher_->OnRenderThreadStarted(thread);
  10341. + thread->AddObserver(dispatcher_.get());
  10342. +}
  10343. +
  10344. +void UserScriptsRendererClient::ConfigurationUpdated() {
  10345. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10346. + LOG(INFO) << "UserScripts: Configuration Updated";
  10347. +
  10348. + struct WatchFrame : public content::RenderFrameVisitor {
  10349. + bool Visit(content::RenderFrame* frame) override {
  10350. + if (frame)
  10351. + UserScriptsRendererClient::GetInstance()->RenderFrameCreated(frame, NULL);
  10352. + return true; // Continue visiting.
  10353. + }
  10354. + };
  10355. + WatchFrame visitor = {};
  10356. + content::RenderFrame::ForEach(&visitor);
  10357. +}
  10358. +
  10359. +void UserScriptsRendererClient::RenderFrameCreated(
  10360. + content::RenderFrame* render_frame,
  10361. + service_manager::BinderRegistry* registry) {
  10362. +
  10363. + auto params = ChromeRenderThreadObserver::GetDynamicParams();
  10364. + enabled_ = params.allow_userscript;
  10365. + if (!enabled_) return;
  10366. +
  10367. + if (loaded_ == false) {
  10368. + loaded_ = true;
  10369. + new user_scripts::ExtensionFrameHelper(render_frame);
  10370. + dispatcher_->OnRenderFrameCreated(render_frame);
  10371. + }
  10372. +}
  10373. +
  10374. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  10375. + if (!enabled_ || !loaded_) return;
  10376. +
  10377. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10378. + if (!frame_helper)
  10379. + return; // The frame is invisible to user scripts.
  10380. +
  10381. + frame_helper->RunScriptsAtDocumentStart();
  10382. + // |frame_helper| and |render_frame| might be dead by now.
  10383. +}
  10384. +
  10385. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  10386. + if (!enabled_ || !loaded_) return;
  10387. +
  10388. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10389. + if (!frame_helper)
  10390. + return; // The frame is invisible to user scripts.
  10391. +
  10392. + frame_helper->RunScriptsAtDocumentEnd();
  10393. + // |frame_helper| and |render_frame| might be dead by now.
  10394. +}
  10395. +
  10396. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  10397. + if (!enabled_ || !loaded_) return;
  10398. +
  10399. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10400. + if (!frame_helper)
  10401. + return; // The frame is invisible to user scripts.
  10402. +
  10403. + frame_helper->RunScriptsAtDocumentIdle();
  10404. + // |frame_helper| and |render_frame| might be dead by now.
  10405. +}
  10406. +
  10407. +}
  10408. \ No newline at end of file
  10409. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10410. new file mode 100755
  10411. --- /dev/null
  10412. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10413. @@ -0,0 +1,37 @@
  10414. +#ifndef USERSCRIPTS_RENDER_CLIENT_H_
  10415. +#define USERSCRIPTS_RENDER_CLIENT_H_
  10416. +
  10417. +#include <memory>
  10418. +#include <string>
  10419. +
  10420. +#include "user_scripts_dispatcher.h"
  10421. +#include "services/service_manager/public/cpp/binder_registry.h"
  10422. +
  10423. +namespace user_scripts {
  10424. +
  10425. +class UserScriptsRendererClient {
  10426. + public:
  10427. + UserScriptsRendererClient(const UserScriptsRendererClient&) = delete;
  10428. + UserScriptsRendererClient& operator=(const UserScriptsRendererClient&) = delete;
  10429. + UserScriptsRendererClient();
  10430. + ~UserScriptsRendererClient();
  10431. +
  10432. + static UserScriptsRendererClient* GetInstance();
  10433. +
  10434. + void RenderThreadStarted();
  10435. + void ConfigurationUpdated();
  10436. + void RenderFrameCreated(content::RenderFrame* render_frame,
  10437. + service_manager::BinderRegistry* registry);
  10438. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  10439. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  10440. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  10441. +
  10442. + private:
  10443. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  10444. + bool enabled_ = false;
  10445. + bool loaded_ = false;
  10446. +};
  10447. +
  10448. +}
  10449. +
  10450. +#endif
  10451. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  10452. new file mode 100755
  10453. --- /dev/null
  10454. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  10455. @@ -0,0 +1,40 @@
  10456. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10457. +// Use of this source code is governed by a BSD-style license that can be
  10458. +// found in the LICENSE file.
  10459. +
  10460. +#include "web_ui_injection_host.h"
  10461. +#include "base/no_destructor.h"
  10462. +
  10463. +namespace {
  10464. +
  10465. +// The default secure CSP to be used in order to prevent remote scripts.
  10466. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  10467. +
  10468. +}
  10469. +
  10470. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  10471. + : InjectionHost(host_id),
  10472. + url_(host_id.id()) {
  10473. +}
  10474. +
  10475. +WebUIInjectionHost::~WebUIInjectionHost() {
  10476. +}
  10477. +
  10478. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  10479. + // Use the main world CSP.
  10480. + // return nullptr;
  10481. +
  10482. + // The isolated world will use its own CSP which blocks remotely hosted
  10483. + // code.
  10484. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  10485. + kDefaultSecureCSP);
  10486. + return default_isolated_world_csp.get();
  10487. +}
  10488. +
  10489. +const GURL& WebUIInjectionHost::url() const {
  10490. + return url_;
  10491. +}
  10492. +
  10493. +const std::string& WebUIInjectionHost::name() const {
  10494. + return id().id();
  10495. +}
  10496. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  10497. new file mode 100755
  10498. --- /dev/null
  10499. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  10500. @@ -0,0 +1,27 @@
  10501. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10502. +// Use of this source code is governed by a BSD-style license that can be
  10503. +// found in the LICENSE file.
  10504. +
  10505. +#ifndef USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10506. +#define USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10507. +
  10508. +#include "injection_host.h"
  10509. +
  10510. +class WebUIInjectionHost : public InjectionHost {
  10511. + public:
  10512. + WebUIInjectionHost(const WebUIInjectionHost&) = delete;
  10513. + WebUIInjectionHost& operator=(const WebUIInjectionHost&) = delete;
  10514. + WebUIInjectionHost(const HostID& host_id);
  10515. + ~WebUIInjectionHost() override;
  10516. +
  10517. + private:
  10518. + // InjectionHost:
  10519. + const std::string* GetContentSecurityPolicy() const override;
  10520. + const GURL& url() const override;
  10521. + const std::string& name() const override;
  10522. +
  10523. + private:
  10524. + GURL url_;
  10525. +};
  10526. +
  10527. +#endif // USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10528. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  10529. new file mode 100755
  10530. --- /dev/null
  10531. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  10532. @@ -0,0 +1,57 @@
  10533. +<?xml version="1.0" encoding="utf-8"?>
  10534. +<grit-part>
  10535. +
  10536. + <!-- Preferences -->
  10537. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  10538. + desc="."
  10539. + formatter_data="android_java">
  10540. + User Scripts
  10541. + </message>
  10542. +
  10543. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  10544. + Activate User Scripts
  10545. + </message>
  10546. +
  10547. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10548. + ON
  10549. + </message>
  10550. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10551. + OFF
  10552. + </message>
  10553. +
  10554. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10555. + Add script
  10556. + </message>
  10557. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  10558. + Experimental support for Greasemonkey-style user scripts.
  10559. + </message>
  10560. +
  10561. + <message name="IDS_SCRIPTS_ITEM_VERSION" desc="." formatter_data="android_java">
  10562. + Version:
  10563. + </message>
  10564. + <message name="IDS_SCRIPTS_ITEM_FILENAME" desc="." formatter_data="android_java">
  10565. + File:
  10566. + </message>
  10567. + <message name="IDS_SCRIPTS_ITEM_URL" desc="." formatter_data="android_java">
  10568. + Url:
  10569. + </message>
  10570. +
  10571. + <message name="IDS_SCRIPTS_VIEW_SOURCE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10572. + View source
  10573. + </message>
  10574. +
  10575. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10576. + Do you want to install this user script from following location?
  10577. +
  10578. +<ph name="FILE">%s</ph>
  10579. +
  10580. +NOTE: only install user scripts that you have verified are secure, user scripts can steal your credentials and data.
  10581. + </message>
  10582. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10583. + Yes
  10584. + </message>
  10585. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10586. + No
  10587. + </message>
  10588. +
  10589. +</grit-part>
  10590. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  10591. --- a/tools/gritsettings/resource_ids.spec
  10592. +++ b/tools/gritsettings/resource_ids.spec
  10593. @@ -661,6 +661,12 @@
  10594. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  10595. "includes": [3720]
  10596. },
  10597. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  10598. + "includes": [6000],
  10599. + },
  10600. + "components/user_scripts/browser/resources/browser_resources.grd": {
  10601. + "includes": [6020],
  10602. + },
  10603. # END components/ section.
  10604. # START ios/ section.
  10605. --
  10606. 2.25.1