Experimental-user-scripts-support.patch 388 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644
  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. ---
  19. chrome/android/BUILD.gn | 5 +
  20. .../android/java/res/xml/main_preferences.xml | 5 +
  21. .../browser/download/DownloadUtils.java | 6 +
  22. .../init/ProcessInitializationHandler.java | 3 +
  23. chrome/android/java_sources.gni | 3 +
  24. chrome/browser/BUILD.gn | 5 +
  25. chrome/browser/about_flags.cc | 5 +
  26. .../browser/chrome_content_browser_client.cc | 3 +-
  27. chrome/browser/flag_descriptions.cc | 5 +
  28. chrome/browser/flag_descriptions.h | 3 +
  29. chrome/browser/prefs/browser_prefs.cc | 2 +
  30. chrome/browser/profiles/BUILD.gn | 1 +
  31. ...hrome_browser_main_extra_parts_profiles.cc | 3 +
  32. chrome/browser/profiles/profile_manager.cc | 9 +
  33. chrome/browser/profiles/renderer_updater.cc | 10 +-
  34. chrome/browser/profiles/renderer_updater.h | 1 +
  35. .../webui/chrome_web_ui_controller_factory.cc | 3 +
  36. chrome/chrome_paks.gni | 2 +
  37. chrome/common/renderer_configuration.mojom | 1 +
  38. chrome/renderer/BUILD.gn | 1 +
  39. .../chrome_content_renderer_client.cc | 37 +
  40. .../renderer/chrome_render_thread_observer.cc | 3 +
  41. components/components_strings.grd | 1 +
  42. components/user_scripts/README.md | 150 ++++
  43. components/user_scripts/android/BUILD.gn | 80 ++
  44. .../java/res/layout/accept_script_item.xml | 160 ++++
  45. .../java/res/layout/accept_script_list.xml | 10 +
  46. .../java/res/layout/scripts_preference.xml | 40 +
  47. .../android/java/res/values/dimens.xml | 11 +
  48. .../java/res/xml/userscripts_preferences.xml | 34 +
  49. .../user_scripts/UserScriptsUtils.java | 84 ++
  50. .../user_scripts/FragmentWindowAndroid.java | 89 ++
  51. .../user_scripts/IUserScriptsUtils.java | 22 +
  52. .../components/user_scripts/ScriptInfo.java | 37 +
  53. .../user_scripts/ScriptListBaseAdapter.java | 163 ++++
  54. .../user_scripts/ScriptListPreference.java | 171 ++++
  55. .../user_scripts/UserScriptsBridge.java | 200 +++++
  56. .../user_scripts/UserScriptsPreferences.java | 116 +++
  57. .../user_scripts/android/java_sources.gni | 18 +
  58. .../android/user_scripts_bridge.cc | 173 ++++
  59. .../android/user_scripts_bridge.h | 31 +
  60. components/user_scripts/browser/BUILD.gn | 82 ++
  61. .../user_scripts/browser/file_task_runner.cc | 40 +
  62. .../user_scripts/browser/file_task_runner.h | 34 +
  63. .../browser/resources/browser_resources.grd | 14 +
  64. .../browser/resources/user-script-ui/BUILD.gn | 12 +
  65. .../user-script-ui/user-scripts-ui.html | 14 +
  66. .../user-script-ui/user-scripts-ui.js | 9 +
  67. .../browser/ui/user_scripts_ui.cc | 148 ++++
  68. .../user_scripts/browser/ui/user_scripts_ui.h | 39 +
  69. .../browser/user_script_loader.cc | 714 ++++++++++++++++
  70. .../user_scripts/browser/user_script_loader.h | 170 ++++
  71. .../browser/user_script_pref_info.cc | 34 +
  72. .../browser/user_script_pref_info.h | 72 ++
  73. .../user_scripts/browser/user_script_prefs.cc | 276 ++++++
  74. .../user_scripts/browser/user_script_prefs.h | 62 ++
  75. .../browser/userscripts_browser_client.cc | 78 ++
  76. .../browser/userscripts_browser_client.h | 62 ++
  77. components/user_scripts/common/BUILD.gn | 49 ++
  78. components/user_scripts/common/constants.h | 21 +
  79. components/user_scripts/common/error_utils.cc | 54 ++
  80. components/user_scripts/common/error_utils.h | 24 +
  81. .../common/extension_message_generator.cc | 29 +
  82. .../common/extension_message_generator.h | 11 +
  83. .../user_scripts/common/extension_messages.cc | 40 +
  84. .../user_scripts/common/extension_messages.h | 71 ++
  85. components/user_scripts/common/host_id.cc | 31 +
  86. components/user_scripts/common/host_id.h | 35 +
  87. .../user_scripts/common/script_constants.h | 33 +
  88. components/user_scripts/common/url_pattern.cc | 803 ++++++++++++++++++
  89. components/user_scripts/common/url_pattern.h | 302 +++++++
  90. .../user_scripts/common/url_pattern_set.cc | 335 ++++++++
  91. .../user_scripts/common/url_pattern_set.h | 161 ++++
  92. components/user_scripts/common/user_script.cc | 325 +++++++
  93. components/user_scripts/common/user_script.h | 403 +++++++++
  94. .../common/user_scripts_features.cc | 32 +
  95. .../common/user_scripts_features.h | 34 +
  96. components/user_scripts/common/view_type.cc | 39 +
  97. components/user_scripts/common/view_type.h | 48 ++
  98. components/user_scripts/renderer/BUILD.gn | 67 ++
  99. .../renderer/extension_frame_helper.cc | 96 +++
  100. .../renderer/extension_frame_helper.h | 92 ++
  101. .../user_scripts/renderer/injection_host.cc | 12 +
  102. .../user_scripts/renderer/injection_host.h | 42 +
  103. .../renderer/resources/greasemonkey_api.js | 82 ++
  104. .../user_scripts_renderer_resources.grd | 14 +
  105. .../user_scripts/renderer/script_context.cc | 215 +++++
  106. .../user_scripts/renderer/script_context.h | 70 ++
  107. .../user_scripts/renderer/script_injection.cc | 343 ++++++++
  108. .../user_scripts/renderer/script_injection.h | 155 ++++
  109. .../renderer/script_injection_callback.cc | 25 +
  110. .../renderer/script_injection_callback.h | 39 +
  111. .../renderer/script_injection_manager.cc | 417 +++++++++
  112. .../renderer/script_injection_manager.h | 102 +++
  113. .../user_scripts/renderer/script_injector.h | 96 +++
  114. .../user_scripts/renderer/scripts_run_info.cc | 31 +
  115. .../user_scripts/renderer/scripts_run_info.h | 70 ++
  116. .../renderer/user_script_injector.cc | 228 +++++
  117. .../renderer/user_script_injector.h | 87 ++
  118. .../user_scripts/renderer/user_script_set.cc | 262 ++++++
  119. .../user_scripts/renderer/user_script_set.h | 102 +++
  120. .../renderer/user_script_set_manager.cc | 77 ++
  121. .../renderer/user_script_set_manager.h | 62 ++
  122. .../renderer/user_scripts_dispatcher.cc | 36 +
  123. .../renderer/user_scripts_dispatcher.h | 48 ++
  124. .../renderer/user_scripts_renderer_client.cc | 105 +++
  125. .../renderer/user_scripts_renderer_client.h | 36 +
  126. .../renderer/web_ui_injection_host.cc | 40 +
  127. .../renderer/web_ui_injection_host.h | 28 +
  128. .../strings/userscripts_strings.grdp | 55 ++
  129. tools/gritsettings/resource_ids.spec | 6 +
  130. 111 files changed, 9584 insertions(+), 2 deletions(-)
  131. create mode 100644 components/user_scripts/README.md
  132. create mode 100755 components/user_scripts/android/BUILD.gn
  133. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_item.xml
  134. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_list.xml
  135. create mode 100644 components/user_scripts/android/java/res/layout/scripts_preference.xml
  136. create mode 100755 components/user_scripts/android/java/res/values/dimens.xml
  137. create mode 100644 components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  138. create mode 100755 components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  139. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  140. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  141. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  142. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  143. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  144. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  145. create mode 100755 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  146. create mode 100644 components/user_scripts/android/java_sources.gni
  147. create mode 100644 components/user_scripts/android/user_scripts_bridge.cc
  148. create mode 100644 components/user_scripts/android/user_scripts_bridge.h
  149. create mode 100755 components/user_scripts/browser/BUILD.gn
  150. create mode 100755 components/user_scripts/browser/file_task_runner.cc
  151. create mode 100755 components/user_scripts/browser/file_task_runner.h
  152. create mode 100644 components/user_scripts/browser/resources/browser_resources.grd
  153. create mode 100644 components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  154. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  155. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  156. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.cc
  157. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.h
  158. create mode 100755 components/user_scripts/browser/user_script_loader.cc
  159. create mode 100755 components/user_scripts/browser/user_script_loader.h
  160. create mode 100644 components/user_scripts/browser/user_script_pref_info.cc
  161. create mode 100644 components/user_scripts/browser/user_script_pref_info.h
  162. create mode 100644 components/user_scripts/browser/user_script_prefs.cc
  163. create mode 100644 components/user_scripts/browser/user_script_prefs.h
  164. create mode 100755 components/user_scripts/browser/userscripts_browser_client.cc
  165. create mode 100755 components/user_scripts/browser/userscripts_browser_client.h
  166. create mode 100755 components/user_scripts/common/BUILD.gn
  167. create mode 100755 components/user_scripts/common/constants.h
  168. create mode 100755 components/user_scripts/common/error_utils.cc
  169. create mode 100755 components/user_scripts/common/error_utils.h
  170. create mode 100755 components/user_scripts/common/extension_message_generator.cc
  171. create mode 100755 components/user_scripts/common/extension_message_generator.h
  172. create mode 100755 components/user_scripts/common/extension_messages.cc
  173. create mode 100755 components/user_scripts/common/extension_messages.h
  174. create mode 100755 components/user_scripts/common/host_id.cc
  175. create mode 100755 components/user_scripts/common/host_id.h
  176. create mode 100755 components/user_scripts/common/script_constants.h
  177. create mode 100755 components/user_scripts/common/url_pattern.cc
  178. create mode 100755 components/user_scripts/common/url_pattern.h
  179. create mode 100755 components/user_scripts/common/url_pattern_set.cc
  180. create mode 100755 components/user_scripts/common/url_pattern_set.h
  181. create mode 100755 components/user_scripts/common/user_script.cc
  182. create mode 100755 components/user_scripts/common/user_script.h
  183. create mode 100644 components/user_scripts/common/user_scripts_features.cc
  184. create mode 100644 components/user_scripts/common/user_scripts_features.h
  185. create mode 100755 components/user_scripts/common/view_type.cc
  186. create mode 100755 components/user_scripts/common/view_type.h
  187. create mode 100755 components/user_scripts/renderer/BUILD.gn
  188. create mode 100755 components/user_scripts/renderer/extension_frame_helper.cc
  189. create mode 100755 components/user_scripts/renderer/extension_frame_helper.h
  190. create mode 100755 components/user_scripts/renderer/injection_host.cc
  191. create mode 100755 components/user_scripts/renderer/injection_host.h
  192. create mode 100755 components/user_scripts/renderer/resources/greasemonkey_api.js
  193. create mode 100755 components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  194. create mode 100755 components/user_scripts/renderer/script_context.cc
  195. create mode 100755 components/user_scripts/renderer/script_context.h
  196. create mode 100755 components/user_scripts/renderer/script_injection.cc
  197. create mode 100755 components/user_scripts/renderer/script_injection.h
  198. create mode 100755 components/user_scripts/renderer/script_injection_callback.cc
  199. create mode 100755 components/user_scripts/renderer/script_injection_callback.h
  200. create mode 100755 components/user_scripts/renderer/script_injection_manager.cc
  201. create mode 100755 components/user_scripts/renderer/script_injection_manager.h
  202. create mode 100755 components/user_scripts/renderer/script_injector.h
  203. create mode 100755 components/user_scripts/renderer/scripts_run_info.cc
  204. create mode 100755 components/user_scripts/renderer/scripts_run_info.h
  205. create mode 100755 components/user_scripts/renderer/user_script_injector.cc
  206. create mode 100755 components/user_scripts/renderer/user_script_injector.h
  207. create mode 100755 components/user_scripts/renderer/user_script_set.cc
  208. create mode 100755 components/user_scripts/renderer/user_script_set.h
  209. create mode 100755 components/user_scripts/renderer/user_script_set_manager.cc
  210. create mode 100755 components/user_scripts/renderer/user_script_set_manager.h
  211. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.cc
  212. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.h
  213. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.cc
  214. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.h
  215. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.cc
  216. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.h
  217. create mode 100755 components/user_scripts/strings/userscripts_strings.grdp
  218. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  219. --- a/chrome/android/BUILD.gn
  220. +++ b/chrome/android/BUILD.gn
  221. @@ -253,6 +253,10 @@ android_resources("chrome_app_java_resources") {
  222. "//third_party/androidx:androidx_preference_preference_java",
  223. "//third_party/androidx:androidx_recyclerview_recyclerview_java",
  224. ]
  225. +
  226. + # this need to be into android_resources("chrome_app_java_resources") section because
  227. + # android:java_resources are packed *_percent.pak and placed in the executable folder
  228. + deps += [ "//components/user_scripts/android:java_resources" ]
  229. }
  230. if (enable_vr) {
  231. @@ -532,6 +536,7 @@ android_library("chrome_java") {
  232. "//components/ukm/android:java",
  233. "//components/url_formatter/android:url_formatter_java",
  234. "//components/user_prefs/android:java",
  235. + "//components/user_scripts/android:java",
  236. "//components/variations/android:variations_java",
  237. "//components/version_info/android:version_constants_java",
  238. "//components/viz/common:common_java",
  239. diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
  240. --- a/chrome/android/java/res/xml/main_preferences.xml
  241. +++ b/chrome/android/java/res/xml/main_preferences.xml
  242. @@ -86,6 +86,11 @@
  243. android:key="useragent_settings"
  244. android:order="20"
  245. android:title="@string/prefs_useragent_settings"/>
  246. + <Preference
  247. + android:fragment="org.chromium.components.user_scripts.UserScriptsPreferences"
  248. + android:key="userscripts_settings"
  249. + android:order="20"
  250. + android:title="@string/prefs_userscripts_settings"/>
  251. <Preference
  252. android:fragment="org.chromium.chrome.browser.language.settings.LanguageSettings"
  253. android:key="languages"
  254. 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
  255. --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  256. +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  257. @@ -68,6 +68,7 @@ import org.chromium.content_public.browser.BrowserStartupController;
  258. import org.chromium.content_public.browser.LoadUrlParams;
  259. import org.chromium.ui.base.DeviceFormFactor;
  260. import org.chromium.ui.widget.Toast;
  261. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  262. import java.io.File;
  263. @@ -419,6 +420,11 @@ public class DownloadUtils {
  264. public static boolean openFile(String filePath, String mimeType, String downloadGuid,
  265. OTRProfileID otrProfileID, String originalUrl, String referrer,
  266. @DownloadOpenSource int source, Context context) {
  267. + if (UserScriptsUtils.getInstance().openFile(filePath, mimeType, downloadGuid,
  268. + originalUrl, referrer,
  269. + getUriForItem(filePath))) {
  270. + return true;
  271. + }
  272. DownloadMetrics.recordDownloadOpen(source, mimeType);
  273. DownloadManagerService service = DownloadManagerService.getDownloadManagerService();
  274. 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
  275. --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  276. +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  277. @@ -113,6 +113,8 @@ import java.util.Date;
  278. import java.util.List;
  279. import java.util.Locale;
  280. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  281. +
  282. /**
  283. * Handles the initialization dependences of the browser process. This is meant to handle the
  284. * initialization that is not tied to any particular Activity, and the logic that should only be
  285. @@ -297,6 +299,7 @@ public class ProcessInitializationHandler {
  286. DefaultBrowserInfo.initBrowserFetcher();
  287. + UserScriptsUtils.Initialize();
  288. AfterStartupTaskUtils.setStartupComplete();
  289. PartnerBrowserCustomizations.getInstance().setOnInitializeAsyncFinished(
  290. diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
  291. --- a/chrome/android/java_sources.gni
  292. +++ b/chrome/android/java_sources.gni
  293. @@ -22,6 +22,7 @@ import("//components/feed/features.gni")
  294. import("//components/offline_pages/buildflags/features.gni")
  295. import("//components/omnibox/browser/test_java_sources.gni")
  296. import("//device/vr/buildflags/buildflags.gni")
  297. +import("//components/user_scripts/android/java_sources.gni")
  298. chrome_java_sources += public_autofill_assistant_java_sources
  299. @@ -59,3 +60,5 @@ if (enable_arcore) {
  300. "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java",
  301. ]
  302. }
  303. +
  304. +chrome_java_sources += userscripts_java_sources
  305. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  306. --- a/chrome/browser/BUILD.gn
  307. +++ b/chrome/browser/BUILD.gn
  308. @@ -3515,6 +3515,11 @@ static_library("browser") {
  309. ]
  310. deps += [ "//chrome/android/modules/dev_ui/provider:native" ]
  311. }
  312. + deps += [
  313. + "//components/user_scripts/common",
  314. + "//components/user_scripts/browser",
  315. + "//components/user_scripts/android",
  316. + ]
  317. } else {
  318. #!is_android
  319. if (!is_chromeos_lacros) {
  320. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
  321. --- a/chrome/browser/about_flags.cc
  322. +++ b/chrome/browser/about_flags.cc
  323. @@ -149,6 +149,7 @@
  324. #include "components/translate/core/browser/translate_ranker_impl.h"
  325. #include "components/translate/core/common/translate_util.h"
  326. #include "components/ui_devtools/switches.h"
  327. +#include "components/user_scripts/common/user_scripts_features.h"
  328. #include "components/version_info/version_info.h"
  329. #include "components/viz/common/features.h"
  330. #include "components/viz/common/switches.h"
  331. @@ -6535,6 +6536,10 @@ const FeatureEntry kFeatureEntries[] = {
  332. FEATURE_VALUE_TYPE(features::kUserDataSnapshot)},
  333. #endif
  334. + {"enable-userscripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  335. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  336. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  337. +
  338. #if defined(OS_WIN)
  339. {"run-video-capture-service-in-browser",
  340. flag_descriptions::kRunVideoCaptureServiceInBrowserProcessName,
  341. diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
  342. --- a/chrome/browser/chrome_content_browser_client.cc
  343. +++ b/chrome/browser/chrome_content_browser_client.cc
  344. @@ -4662,7 +4662,8 @@ ChromeContentBrowserClient::CreateURLLoaderThrottles(
  345. chrome::mojom::DynamicParams dynamic_params = {
  346. profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch),
  347. profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict),
  348. - profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)};
  349. + profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps),
  350. + false /*-> allow_userscript, don't care */};
  351. result.push_back(std::make_unique<GoogleURLLoaderThrottle>(
  352. #if defined(OS_ANDROID)
  353. client_data_header, is_tab_large_enough,
  354. diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
  355. --- a/chrome/browser/flag_descriptions.cc
  356. +++ b/chrome/browser/flag_descriptions.cc
  357. @@ -5382,6 +5382,11 @@ const char kUserDataSnapshotDescription[] =
  358. "update and restoring them after a version rollback.";
  359. #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
  360. +const char kEnableLoggingUserScriptsName[] = "Enable logging user scripts component";
  361. +const char kEnableLoggingUserScriptsDescription[] =
  362. + "Enables logging for troubleshooting feature. "
  363. + "Enabling logs may make browsing slower.";
  364. +
  365. #if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MAC)
  366. const char kWebShareName[] = "Web Share";
  367. const char kWebShareDescription[] =
  368. diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
  369. --- a/chrome/browser/flag_descriptions.h
  370. +++ b/chrome/browser/flag_descriptions.h
  371. @@ -3134,6 +3134,9 @@ extern const char kUserDataSnapshotName[];
  372. extern const char kUserDataSnapshotDescription[];
  373. #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
  374. +extern const char kEnableLoggingUserScriptsName[];
  375. +extern const char kEnableLoggingUserScriptsDescription[];
  376. +
  377. #if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MAC)
  378. extern const char kWebShareName[];
  379. extern const char kWebShareDescription[];
  380. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  381. --- a/chrome/browser/prefs/browser_prefs.cc
  382. +++ b/chrome/browser/prefs/browser_prefs.cc
  383. @@ -235,6 +235,7 @@
  384. #include "components/ntp_tiles/popular_sites_impl.h"
  385. #include "components/permissions/contexts/geolocation_permission_context_android.h"
  386. #include "components/query_tiles/tile_service_prefs.h"
  387. +#include "components/user_scripts/browser/user_script_prefs.h"
  388. #else // defined(OS_ANDROID)
  389. #include "chrome/browser/cart/cart_service.h"
  390. #include "chrome/browser/device_api/device_service_impl.h"
  391. @@ -1214,6 +1215,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
  392. translate::TranslatePrefs::RegisterProfilePrefs(registry);
  393. omnibox::RegisterProfilePrefs(registry);
  394. ZeroSuggestProvider::RegisterProfilePrefs(registry);
  395. + user_scripts::UserScriptsPrefs::RegisterProfilePrefs(registry);
  396. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  397. RegisterSessionServiceLogProfilePrefs(registry);
  398. diff --git a/chrome/browser/profiles/BUILD.gn b/chrome/browser/profiles/BUILD.gn
  399. --- a/chrome/browser/profiles/BUILD.gn
  400. +++ b/chrome/browser/profiles/BUILD.gn
  401. @@ -45,6 +45,7 @@ source_set("profile") {
  402. "//components/profile_metrics",
  403. "//components/sync/driver",
  404. "//components/variations",
  405. + "//components/user_scripts/browser",
  406. "//content/public/browser",
  407. "//extensions/buildflags",
  408. ]
  409. diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  410. --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  411. +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  412. @@ -217,6 +217,8 @@
  413. #include "chrome/browser/lacros/cert_db_initializer_factory.h"
  414. #endif
  415. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  416. +
  417. namespace chrome {
  418. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  419. @@ -517,6 +519,7 @@ void ChromeBrowserMainExtraPartsProfiles::
  420. #endif
  421. WebDataServiceFactory::GetInstance();
  422. webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
  423. + user_scripts::UserScriptsBrowserClient::GetInstance();
  424. }
  425. void ChromeBrowserMainExtraPartsProfiles::PreProfileInit() {
  426. diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
  427. --- a/chrome/browser/profiles/profile_manager.cc
  428. +++ b/chrome/browser/profiles/profile_manager.cc
  429. @@ -118,6 +118,8 @@
  430. #include "extensions/common/manifest.h"
  431. #endif
  432. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  433. +
  434. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  435. #include "chrome/browser/sessions/app_session_service_factory.h"
  436. #include "chrome/browser/sessions/session_service_factory.h"
  437. @@ -1538,6 +1540,13 @@ void ProfileManager::DoFinalInitForServices(Profile* profile,
  438. }
  439. #endif
  440. +
  441. + user_scripts::UserScriptsBrowserClient* userscript_client =
  442. + user_scripts::UserScriptsBrowserClient::GetInstance();
  443. + if (userscript_client) {
  444. + userscript_client->SetProfile(profile);
  445. + }
  446. +
  447. #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  448. // Initialization needs to happen after extension system initialization (for
  449. // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the
  450. diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
  451. --- a/chrome/browser/profiles/renderer_updater.cc
  452. +++ b/chrome/browser/profiles/renderer_updater.cc
  453. @@ -29,6 +29,8 @@
  454. #include "chrome/browser/ash/login/signin/oauth2_login_manager_factory.h"
  455. #endif
  456. +#include "components/user_scripts/browser/user_script_prefs.h"
  457. +
  458. namespace {
  459. #if BUILDFLAG(ENABLE_EXTENSIONS)
  460. @@ -79,6 +81,7 @@ RendererUpdater::RendererUpdater(Profile* profile) : profile_(profile) {
  461. force_google_safesearch_.Init(prefs::kForceGoogleSafeSearch, pref_service);
  462. force_youtube_restrict_.Init(prefs::kForceYouTubeRestrict, pref_service);
  463. allowed_domains_for_apps_.Init(prefs::kAllowedDomainsForApps, pref_service);
  464. + activate_userscripts_.Init(user_scripts::prefs::kUserScriptsEnabled, pref_service);
  465. pref_change_registrar_.Init(pref_service);
  466. pref_change_registrar_.Add(
  467. @@ -93,6 +96,10 @@ RendererUpdater::RendererUpdater(Profile* profile) : profile_(profile) {
  468. prefs::kAllowedDomainsForApps,
  469. base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  470. base::Unretained(this)));
  471. + pref_change_registrar_.Add(
  472. + user_scripts::prefs::kUserScriptsEnabled,
  473. + base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  474. + base::Unretained(this)));
  475. }
  476. RendererUpdater::~RendererUpdater() {
  477. @@ -241,5 +248,6 @@ void RendererUpdater::UpdateRenderer(
  478. ->SetConfiguration(chrome::mojom::DynamicParams::New(
  479. force_google_safesearch_.GetValue(),
  480. force_youtube_restrict_.GetValue(),
  481. - allowed_domains_for_apps_.GetValue()));
  482. + allowed_domains_for_apps_.GetValue(),
  483. + activate_userscripts_.GetValue()));
  484. }
  485. diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
  486. --- a/chrome/browser/profiles/renderer_updater.h
  487. +++ b/chrome/browser/profiles/renderer_updater.h
  488. @@ -82,6 +82,7 @@ class RendererUpdater : public KeyedService,
  489. // Prefs that we sync to the renderers.
  490. BooleanPrefMember force_google_safesearch_;
  491. + BooleanPrefMember activate_userscripts_;
  492. IntegerPrefMember force_youtube_restrict_;
  493. StringPrefMember allowed_domains_for_apps_;
  494. diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  495. --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  496. +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  497. @@ -85,6 +85,7 @@
  498. #include "components/security_interstitials/content/urls.h"
  499. #include "components/signin/public/base/signin_buildflags.h"
  500. #include "components/site_engagement/content/site_engagement_service.h"
  501. +#include "components/user_scripts/browser/ui/user_scripts_ui.h"
  502. #include "content/public/browser/web_contents.h"
  503. #include "content/public/browser/web_ui.h"
  504. #include "content/public/common/content_client.h"
  505. @@ -681,6 +682,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
  506. return &NewWebUI<UserActionsUI>;
  507. if (url.host_piece() == chrome::kChromeUIVersionHost)
  508. return &NewWebUI<VersionUI>;
  509. + if (url.host_piece() == user_scripts::kChromeUIUserScriptsHost)
  510. + return &NewWebUI<user_scripts::UserScriptsUI>;
  511. #if !defined(OS_ANDROID)
  512. #if !defined(OS_CHROMEOS)
  513. diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
  514. --- a/chrome/chrome_paks.gni
  515. +++ b/chrome/chrome_paks.gni
  516. @@ -105,6 +105,7 @@ template("chrome_extra_paks") {
  517. "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak",
  518. "$root_gen_dir/ui/resources/webui_generated_resources.pak",
  519. "$root_gen_dir/ui/resources/webui_resources.pak",
  520. + "$root_gen_dir/chrome/userscripts_browser_resources.pak",
  521. ]
  522. deps = [
  523. "//base/tracing/protos:chrome_track_event_resources",
  524. @@ -120,6 +121,7 @@ template("chrome_extra_paks") {
  525. "//third_party/blink/public:devtools_inspector_resources",
  526. "//third_party/blink/public:resources",
  527. "//ui/resources",
  528. + "//components/user_scripts/browser:userscripts_browser_resources_grit",
  529. ]
  530. if (defined(invoker.deps)) {
  531. deps += invoker.deps
  532. diff --git a/chrome/common/renderer_configuration.mojom b/chrome/common/renderer_configuration.mojom
  533. --- a/chrome/common/renderer_configuration.mojom
  534. +++ b/chrome/common/renderer_configuration.mojom
  535. @@ -12,6 +12,7 @@ struct DynamicParams {
  536. bool force_safe_search = true;
  537. int32 youtube_restrict = 0;
  538. string allowed_domains_for_apps;
  539. + bool allow_userscript = false;
  540. };
  541. interface ChromeOSListener {
  542. diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
  543. --- a/chrome/renderer/BUILD.gn
  544. +++ b/chrome/renderer/BUILD.gn
  545. @@ -172,6 +172,7 @@ static_library("renderer") {
  546. "//components/feed:feature_list",
  547. "//components/feed/content/renderer:feed_renderer",
  548. "//components/history_clusters/core",
  549. + "//components/user_scripts/renderer",
  550. "//components/network_hints/renderer",
  551. "//components/no_state_prefetch/common",
  552. "//components/no_state_prefetch/renderer",
  553. diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
  554. --- a/chrome/renderer/chrome_content_renderer_client.cc
  555. +++ b/chrome/renderer/chrome_content_renderer_client.cc
  556. @@ -253,6 +253,9 @@
  557. #include "chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h"
  558. #endif
  559. +#include "components/user_scripts/common/user_scripts_features.h"
  560. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  561. +
  562. using autofill::AutofillAgent;
  563. using autofill::PasswordAutofillAgent;
  564. using autofill::PasswordGenerationAgent;
  565. @@ -425,6 +428,12 @@ void ChromeContentRendererClient::RenderThreadStarted() {
  566. WebString::FromASCII(extensions::kExtensionScheme));
  567. #endif
  568. + user_scripts::UserScriptsRendererClient* userscript_client =
  569. + user_scripts::UserScriptsRendererClient::GetInstance();
  570. + if (userscript_client) {
  571. + userscript_client->RenderThreadStarted();
  572. + }
  573. +
  574. #if BUILDFLAG(ENABLE_SPELLCHECK)
  575. if (!spellcheck_)
  576. InitSpellCheck();
  577. @@ -561,6 +570,13 @@ void ChromeContentRendererClient::RenderFrameCreated(
  578. render_frame, registry);
  579. #endif
  580. + user_scripts::UserScriptsRendererClient* userscript_client =
  581. + user_scripts::UserScriptsRendererClient::GetInstance();
  582. + if (userscript_client) {
  583. + userscript_client->RenderFrameCreated(
  584. + render_frame, registry);
  585. + }
  586. +
  587. #if BUILDFLAG(ENABLE_PLUGINS)
  588. new PepperHelper(render_frame);
  589. #endif
  590. @@ -1547,7 +1563,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentStart(
  591. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentStart(
  592. render_frame);
  593. // |render_frame| might be dead by now.
  594. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  595. #endif
  596. + user_scripts::UserScriptsRendererClient* userscript_client =
  597. + user_scripts::UserScriptsRendererClient::GetInstance();
  598. + if (userscript_client) {
  599. + userscript_client->RunScriptsAtDocumentStart(
  600. + render_frame);
  601. + }
  602. }
  603. void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  604. @@ -1556,7 +1579,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  605. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentEnd(
  606. render_frame);
  607. // |render_frame| might be dead by now.
  608. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  609. #endif
  610. + user_scripts::UserScriptsRendererClient* userscript_client =
  611. + user_scripts::UserScriptsRendererClient::GetInstance();
  612. + if (userscript_client) {
  613. + userscript_client->RunScriptsAtDocumentEnd(
  614. + render_frame);
  615. + }
  616. }
  617. void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  618. @@ -1565,7 +1595,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  619. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentIdle(
  620. render_frame);
  621. // |render_frame| might be dead by now.
  622. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  623. #endif
  624. + user_scripts::UserScriptsRendererClient* userscript_client =
  625. + user_scripts::UserScriptsRendererClient::GetInstance();
  626. + if (userscript_client) {
  627. + userscript_client->RunScriptsAtDocumentIdle(
  628. + render_frame);
  629. + }
  630. }
  631. void ChromeContentRendererClient::
  632. diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc
  633. --- a/chrome/renderer/chrome_render_thread_observer.cc
  634. +++ b/chrome/renderer/chrome_render_thread_observer.cc
  635. @@ -59,6 +59,8 @@
  636. #include "third_party/blink/public/web/web_security_policy.h"
  637. #include "third_party/blink/public/web/web_view.h"
  638. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  639. +
  640. #if BUILDFLAG(ENABLE_EXTENSIONS)
  641. #include "chrome/renderer/extensions/extension_localization_peer.h"
  642. #endif
  643. @@ -256,6 +258,7 @@ void ChromeRenderThreadObserver::SetInitialConfiguration(
  644. void ChromeRenderThreadObserver::SetConfiguration(
  645. chrome::mojom::DynamicParamsPtr params) {
  646. *GetDynamicConfigParams() = std::move(*params);
  647. + user_scripts::UserScriptsRendererClient::GetInstance()->ConfigurationUpdated();
  648. }
  649. void ChromeRenderThreadObserver::SetContentSettingRules(
  650. diff --git a/components/components_strings.grd b/components/components_strings.grd
  651. --- a/components/components_strings.grd
  652. +++ b/components/components_strings.grd
  653. @@ -335,6 +335,7 @@
  654. <part file="undo_strings.grdp" />
  655. <part file="version_ui_strings.grdp" />
  656. <part file="webapps_strings.grdp" />
  657. + <part file="user_scripts/strings/userscripts_strings.grdp" />
  658. <if expr="not is_android and not is_ios">
  659. <part file="management_strings.grdp" />
  660. diff --git a/components/user_scripts/README.md b/components/user_scripts/README.md
  661. new file mode 100644
  662. --- /dev/null
  663. +++ b/components/user_scripts/README.md
  664. @@ -0,0 +1,150 @@
  665. +# Userscripts support for Bromite
  666. +
  667. +UserScript support is under user setting currently disabled by default: when disabled, no code that can impact navigation safety is active.
  668. +
  669. +Activation allows the use of userscripts in Bromite. It is possible to add them in two ways:
  670. +- by selecting files from the file picker in the settings
  671. +- downloading the scripts and opening it from downloads (only if ends with .user.js)
  672. +The new imported scripts are disabled by default: they can be activated via the menu visible on the ui.
  673. +
  674. +Userscript support is currently the one provided by the desktop version. The enabled headers are:
  675. +
  676. +- `@name`
  677. +- `@version`
  678. +- `@description`
  679. +- `@url` or `@homepage`
  680. +- `@include`, `@exclude`, `@match`, `@exclude_match` for the url pattern (only http e https)
  681. +- `@run-at`
  682. + - `document-start`
  683. + Start the script after the documentElement is created, but before anything else happens
  684. + - `document-end`
  685. + Start the script after the entire document is parsed. Same as DOMContentLoaded
  686. + - `document-idle`
  687. + 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
  688. +
  689. +The url-patterns are so defined:
  690. +```
  691. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  692. +// <scheme> := '*' | 'http' | 'https'
  693. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  694. +// '*.' <anychar except '/' and '*'>+
  695. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  696. +// <path> := '/' <any chars>
  697. +//
  698. +// * Host is not used when the scheme is 'file'.
  699. +// * The path can have embedded '*' characters which act as glob wildcards.
  700. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  701. +// a valid scheme (as specified by valid_schemes_).
  702. +// * The '*' scheme pattern excludes file URLs.
  703. +//
  704. +// Examples of valid patterns:
  705. +// - http://*/*
  706. +// - http://*/foo*
  707. +// - https://*.google.com/foo*bar
  708. +// - file://monkey*
  709. +// - http://127.0.0.1/*
  710. +// - http://[2607:f8b0:4005:805::200e]/*
  711. +//
  712. +// Examples of invalid patterns:
  713. +// - http://* -- path not specified
  714. +// - http://*foo/bar -- * not allowed as substring of host component
  715. +// - http://foo.*.bar/baz -- * must be first component
  716. +// - http:/bar -- scheme separator not found
  717. +// - foo://* -- invalid scheme
  718. +// - chrome:// -- we don't support chrome internal URLs
  719. +```
  720. +
  721. +---
  722. +## **Beware of the scripts you enter: they can be a source of security problems, you are injecting code into your navigation**.
  723. +---
  724. +## Technical aspects
  725. +
  726. +`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.
  727. +
  728. +In `user_scripts/browser` you find the actual management (in the browser process) and in `android` basically the settings ui.
  729. +
  730. +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.
  731. +
  732. +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.
  733. +
  734. +There is also support for an on-line help at https://github.com/bromite/bromite/wiki/UserScripts.
  735. +
  736. +
  737. +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.
  738. +
  739. +for userscripts_browser_client.cc
  740. +- `chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc`
  741. +builds the browser side. also gpu process passes here, but the call is avoided.
  742. +
  743. +- `chrome/browser/profiles/profile_manager.cc`
  744. +set the profile
  745. +
  746. +for renderer/user_scripts_renderer_client.cc
  747. +- `chrome/renderer/chrome_content_renderer_client.cc`
  748. +at the renderer side
  749. +
  750. +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`).
  751. +
  752. +## BROWSER PROCESS
  753. +Once the profile is set, it istance the `components/user_scripts/browser/user_script_loader.cc` and starts it.
  754. +This loads all the files in the folder into the runner file and interprets them. Control then passes to
  755. +`components/user_scripts/browser/user_script_prefs.cc` which verifies through the default profile what the user wants active.
  756. +At that point it passes through IPC to the renderer only the list of active scripts.
  757. +
  758. +## RENDERER PROCESS
  759. +Each time a frame is created, the script pattern is checked and it is injected into the three stages (START, IDLE, END).
  760. +The logic is all in `components/user_scripts/renderer/user_script_set.cc`.
  761. +
  762. +## Simple example
  763. +Here you find a working example that eliminates the google popup, useful in always incognito:
  764. +```
  765. +// ==UserScript==
  766. +// @name Remove Google Consent
  767. +// @namespace google
  768. +// @version 0.0.1
  769. +// @description Autohide Accepts Cookies
  770. +// @author uazo
  771. +// @match https://*.google.com/search?*
  772. +// @grant none
  773. +// @run-at document-start
  774. +// ==/UserScript==
  775. +
  776. +(function() {
  777. + 'use strict';
  778. +
  779. + var prepareStyleSheet = function() {
  780. + var style = document.createElement('style');
  781. + //style.setAttribute('media', 'screen');
  782. + style.appendChild(document.createTextNode(''));
  783. + document.head.appendChild(style);
  784. + style.sheet.insertRule('body { overflow:scroll !important;position:unset !important }');
  785. + };
  786. +
  787. + var hideConsent = function() {
  788. + document.getElementById("lb").style.display = "none";
  789. + };
  790. +
  791. + var checkElementThenRun = function(selector, func) {
  792. + var el = document.querySelector(selector);
  793. + if ( el == null ) {
  794. + if (window.requestAnimationFrame != undefined) {
  795. + window.requestAnimationFrame(function(){ checkElementThenRun(selector, func)});
  796. + } else {
  797. + document.addEventListener('readystatechange', function(e) {
  798. + if (document.readyState == 'complete') {
  799. + func();
  800. + }
  801. + });
  802. + }
  803. + } else {
  804. + func();
  805. + }
  806. + }
  807. +
  808. + document.cookie = 'CONSENT=YES+IT.it+V13+BX;domain=.google.com';
  809. + checkElementThenRun('head', prepareStyleSheet);
  810. + checkElementThenRun('#lb', hideConsent);
  811. +})();
  812. +```
  813. +
  814. +See also: https://github.com/bromite/bromite/pull/857
  815. diff --git a/components/user_scripts/android/BUILD.gn b/components/user_scripts/android/BUILD.gn
  816. new file mode 100755
  817. --- /dev/null
  818. +++ b/components/user_scripts/android/BUILD.gn
  819. @@ -0,0 +1,80 @@
  820. +# This file is part of Bromite.
  821. +
  822. +# Bromite is free software: you can redistribute it and/or modify
  823. +# it under the terms of the GNU General Public License as published by
  824. +# the Free Software Foundation, either version 3 of the License, or
  825. +# (at your option) any later version.
  826. +
  827. +# Bromite is distributed in the hope that it will be useful,
  828. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  829. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  830. +# GNU General Public License for more details.
  831. +
  832. +# You should have received a copy of the GNU General Public License
  833. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  834. +
  835. +import("//build/config/android/rules.gni")
  836. +
  837. +generate_jni("user_scripts_jni_headers") {
  838. + sources = [ "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java" ]
  839. +}
  840. +
  841. +android_resources("java_resources") {
  842. + sources = [
  843. + "java/res/xml/userscripts_preferences.xml",
  844. + "java/res/layout/accept_script_item.xml",
  845. + "java/res/layout/accept_script_list.xml",
  846. + "java/res/layout/scripts_preference.xml",
  847. + "java/res/values/dimens.xml"
  848. + ]
  849. +
  850. + deps = [
  851. + "//components/browser_ui/strings/android:browser_ui_strings_grd",
  852. + "//components/browser_ui/styles/android:java_resources",
  853. + "//components/strings:components_strings_grd",
  854. + "//ui/android:ui_java_resources",
  855. + ]
  856. +}
  857. +
  858. +android_library("java") {
  859. + sources = [
  860. + "java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java",
  861. + "java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java",
  862. + "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java",
  863. + "java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java",
  864. + "java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java",
  865. + "java/src/org/chromium/components/user_scripts/ScriptListPreference.java",
  866. + "java/src/org/chromium/components/user_scripts/ScriptInfo.java",
  867. + ]
  868. + deps = [
  869. + ":java_resources",
  870. + "//base:base_java",
  871. + "//base:jni_java",
  872. + "//components/embedder_support/android:browser_context_java",
  873. + "//components/browser_ui/settings/android:java",
  874. + "//components/browser_ui/widget/android:java",
  875. + "//content/public/android:content_java",
  876. + "//components/prefs/android:java",
  877. + "//third_party/android_deps:android_support_v7_appcompat_java",
  878. + "//third_party/androidx:androidx_annotation_annotation_java",
  879. + "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
  880. + "//third_party/androidx:androidx_preference_preference_java",
  881. + "//ui/android:ui_java",
  882. + ]
  883. + resources_package = "org.chromium.components.user_scripts"
  884. + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
  885. +}
  886. +
  887. +source_set("android") {
  888. + sources = [
  889. + "user_scripts_bridge.cc",
  890. + "user_scripts_bridge.h",
  891. + ]
  892. + deps = [
  893. + ":user_scripts_jni_headers",
  894. + "//base",
  895. + "//components/user_scripts/browser",
  896. + "//components/permissions",
  897. + "//content/public/browser",
  898. + ]
  899. +}
  900. 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
  901. new file mode 100644
  902. --- /dev/null
  903. +++ b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  904. @@ -0,0 +1,160 @@
  905. +<?xml version="1.0" encoding="utf-8"?>
  906. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  907. + Use of this source code is governed by a BSD-style license that can be
  908. + found in the LICENSE file. -->
  909. +
  910. +<LinearLayout
  911. + xmlns:android="http://schemas.android.com/apk/res/android"
  912. + xmlns:app="http://schemas.android.com/apk/res-auto"
  913. + xmlns:tools="http://schemas.android.com/tools"
  914. + android:layout_width="match_parent"
  915. + android:layout_height="wrap_content"
  916. + android:orientation="vertical"
  917. + android:layout_gravity="center_vertical" >
  918. +
  919. + <LinearLayout
  920. + android:layout_marginStart="0dp"
  921. + android:paddingStart="@dimen/draggable_list_item_padding"
  922. + android:paddingEnd="@dimen/draggable_list_item_padding"
  923. + style="@style/ListItemContainer">
  924. +
  925. + <Switch
  926. + android:id="@+id/switch_widget"
  927. + android:layout_width="wrap_content"
  928. + android:layout_height="wrap_content"
  929. + android:paddingEnd="15dp"
  930. + android:focusable="false"
  931. + android:background="@null" />
  932. +
  933. + <LinearLayout
  934. + android:layout_width="0dp"
  935. + android:layout_height="wrap_content"
  936. + android:layout_weight="1"
  937. + android:orientation="vertical"
  938. + android:layout_gravity="center_vertical" >
  939. +
  940. + <TextView
  941. + android:id="@+id/title"
  942. + android:layout_width="match_parent"
  943. + android:layout_height="wrap_content"
  944. + style="@style/PreferenceTitle" />
  945. +
  946. + <TextView
  947. + android:id="@+id/description"
  948. + android:layout_width="match_parent"
  949. + android:layout_height="wrap_content"
  950. + style="@style/PreferenceSummary" />
  951. +
  952. + <LinearLayout
  953. + android:layout_width="match_parent"
  954. + android:layout_height="wrap_content"
  955. + android:layout_weight="1"
  956. + android:paddingTop="5dp"
  957. + android:layout_gravity="center_vertical" >
  958. +
  959. + <TextView
  960. + android:layout_width="wrap_content"
  961. + android:layout_height="wrap_content"
  962. + android:paddingEnd="5dp"
  963. + style="@style/PreferenceSummary"
  964. + android:text="@string/scripts_item_version"
  965. + android:textStyle="bold" />
  966. +
  967. + <TextView
  968. + android:id="@+id/version"
  969. + android:layout_width="match_parent"
  970. + android:layout_height="wrap_content"
  971. + style="@style/PreferenceSummary" />
  972. +
  973. + </LinearLayout>
  974. +
  975. + <LinearLayout
  976. + android:layout_width="match_parent"
  977. + android:layout_height="wrap_content"
  978. + android:layout_weight="1"
  979. + android:layout_gravity="center_vertical" >
  980. +
  981. + <TextView
  982. + android:layout_width="wrap_content"
  983. + android:layout_height="wrap_content"
  984. + android:paddingEnd="5dp"
  985. + style="@style/PreferenceSummary"
  986. + android:text="@string/scripts_item_filename"
  987. + android:textStyle="bold" />
  988. +
  989. + <TextView
  990. + android:id="@+id/file"
  991. + android:layout_width="match_parent"
  992. + android:layout_height="wrap_content"
  993. + style="@style/PreferenceSummary" />
  994. +
  995. + </LinearLayout>
  996. +
  997. + <LinearLayout
  998. + android:id="@+id/url_container"
  999. + android:layout_width="match_parent"
  1000. + android:layout_height="wrap_content"
  1001. + android:layout_weight="1"
  1002. + android:layout_gravity="center_vertical" >
  1003. +
  1004. + <TextView
  1005. + android:layout_width="wrap_content"
  1006. + android:layout_height="wrap_content"
  1007. + android:paddingEnd="5dp"
  1008. + style="@style/PreferenceSummary"
  1009. + android:text="@string/scripts_item_url"
  1010. + android:textStyle="bold" />
  1011. +
  1012. + <TextView
  1013. + android:id="@+id/url"
  1014. + android:layout_width="match_parent"
  1015. + android:layout_height="wrap_content"
  1016. + android:autoLink="web"
  1017. + android:focusable="true"
  1018. + android:linksClickable="true" />
  1019. +
  1020. + </LinearLayout>
  1021. +
  1022. + </LinearLayout>
  1023. +
  1024. + <org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
  1025. + android:id="@+id/more"
  1026. + android:layout_width="wrap_content"
  1027. + android:layout_height="match_parent"
  1028. + android:paddingStart="@dimen/default_list_row_padding"
  1029. + android:paddingEnd="@dimen/default_list_row_padding"
  1030. + android:background="@null"
  1031. + android:src="@drawable/ic_more_vert_24dp"
  1032. + app:menuMaxWidth="@dimen/pref_scripts_item_popup_width"
  1033. + app:tint="@color/default_icon_color_tint_list"
  1034. + tools:ignore="ContentDescription" />
  1035. +
  1036. + </LinearLayout>
  1037. +
  1038. + <LinearLayout
  1039. + android:id="@+id/error_layout"
  1040. + android:layout_marginStart="0dp"
  1041. + android:paddingStart="@dimen/draggable_list_item_padding"
  1042. + android:paddingEnd="2dp"
  1043. + android:layout_width="match_parent"
  1044. + android:layout_height="wrap_content"
  1045. + style="@style/ListItemContainer">
  1046. +
  1047. + <org.chromium.ui.widget.ChromeImageView
  1048. + android:id="@+id/icon"
  1049. + android:layout_width="40dp"
  1050. + android:layout_height="wrap_content"
  1051. + android:paddingEnd="15dp"
  1052. + android:adjustViewBounds="true"
  1053. + android:importantForAccessibility="no"
  1054. + app:srcCompat="@drawable/ic_error_outline_red_24dp"/>
  1055. +
  1056. + <TextView
  1057. + android:id="@+id/error"
  1058. + android:layout_width="match_parent"
  1059. + android:layout_height="wrap_content"
  1060. + android:textColor="#F00"
  1061. + style="@style/PreferenceSummary" />
  1062. +
  1063. + </LinearLayout>
  1064. +</LinearLayout>
  1065. \ No newline at end of file
  1066. 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
  1067. new file mode 100644
  1068. --- /dev/null
  1069. +++ b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  1070. @@ -0,0 +1,10 @@
  1071. +<?xml version="1.0" encoding="utf-8"?>
  1072. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  1073. + Use of this source code is governed by a BSD-style license that can be
  1074. + found in the LICENSE file. -->
  1075. +
  1076. +<androidx.recyclerview.widget.RecyclerView
  1077. + xmlns:android="http://schemas.android.com/apk/res/android"
  1078. + android:id="@+id/script_list"
  1079. + android:layout_width="match_parent"
  1080. + android:layout_height="wrap_content" />
  1081. \ No newline at end of file
  1082. diff --git a/components/user_scripts/android/java/res/layout/scripts_preference.xml b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  1083. new file mode 100644
  1084. --- /dev/null
  1085. +++ b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  1086. @@ -0,0 +1,40 @@
  1087. +<?xml version="1.0" encoding="utf-8"?>
  1088. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  1089. + Use of this source code is governed by a BSD-style license that can be
  1090. + found in the LICENSE file. -->
  1091. +
  1092. +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  1093. + android:id="@+id/accept_scripts_list_container"
  1094. + style="@style/PreferenceLayout"
  1095. + android:layout_width="match_parent"
  1096. + android:layout_height="wrap_content"
  1097. + android:paddingStart="0dp"
  1098. + android:paddingEnd="0dp"
  1099. + android:padding="0dp"
  1100. + android:orientation="vertical" >
  1101. +
  1102. + <TextView
  1103. + android:layout_width="match_parent"
  1104. + android:layout_height="wrap_content"
  1105. + android:padding="@dimen/draggable_list_item_padding"
  1106. + android:text="@string/scripts_list_description" />
  1107. +
  1108. + <FrameLayout
  1109. + android:id="@android:id/widget_frame"
  1110. + android:layout_width="match_parent"
  1111. + android:layout_height="wrap_content" />
  1112. +
  1113. + <TextView
  1114. + android:id="@+id/add_script"
  1115. + android:layout_width="match_parent"
  1116. + android:layout_height="wrap_content"
  1117. + android:background="?attr/selectableItemBackground"
  1118. + android:clickable="true"
  1119. + android:gravity="center_vertical"
  1120. + android:padding="@dimen/draggable_list_item_padding"
  1121. + android:paddingStart="@dimen/pref_scripts_add_button_padding"
  1122. + android:drawablePadding="@dimen/pref_scripts_add_button_padding"
  1123. + android:text="@string/add_script"
  1124. + style="@style/PreferenceTitle" />
  1125. +
  1126. +</LinearLayout>
  1127. \ No newline at end of file
  1128. diff --git a/components/user_scripts/android/java/res/values/dimens.xml b/components/user_scripts/android/java/res/values/dimens.xml
  1129. new file mode 100755
  1130. --- /dev/null
  1131. +++ b/components/user_scripts/android/java/res/values/dimens.xml
  1132. @@ -0,0 +1,11 @@
  1133. +<?xml version="1.0" encoding="utf-8"?>
  1134. +<!-- Copyright 2014 The Chromium Authors. All rights reserved.
  1135. + Use of this source code is governed by a BSD-style license that can be
  1136. + found in the LICENSE file. -->
  1137. +
  1138. +<resources xmlns:tools="http://schemas.android.com/tools">
  1139. +
  1140. + <dimen name="pref_scripts_add_button_padding">24dp</dimen>
  1141. + <dimen name="pref_scripts_item_popup_width">260dp</dimen>
  1142. +
  1143. +</resources>
  1144. diff --git a/components/user_scripts/android/java/res/xml/userscripts_preferences.xml b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1145. new file mode 100644
  1146. --- /dev/null
  1147. +++ b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1148. @@ -0,0 +1,34 @@
  1149. +<?xml version="1.0" encoding="utf-8"?>
  1150. +<!--
  1151. + This file is part of Bromite.
  1152. +
  1153. + Bromite is free software: you can redistribute it and/or modify
  1154. + it under the terms of the GNU General Public License as published by
  1155. + the Free Software Foundation, either version 3 of the License, or
  1156. + (at your option) any later version.
  1157. +
  1158. + Bromite is distributed in the hope that it will be useful,
  1159. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1160. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1161. + GNU General Public License for more details.
  1162. +
  1163. + You should have received a copy of the GNU General Public License
  1164. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1165. +-->
  1166. +
  1167. +<PreferenceScreen
  1168. + xmlns:android="http://schemas.android.com/apk/res/android"
  1169. + xmlns:app="http://schemas.android.com/apk/res-auto">
  1170. +
  1171. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  1172. + android:key="enabled_switch"
  1173. + android:title="@string/option_userscript_flag"
  1174. + android:summaryOn="@string/option_userscript_flag_on"
  1175. + android:summaryOff="@string/option_userscript_flag_off" />
  1176. +
  1177. + <org.chromium.components.user_scripts.ScriptListPreference
  1178. + android:key="script_list"
  1179. + android:layout="@layout/scripts_preference"
  1180. + android:widgetLayout="@layout/accept_script_list" />
  1181. +
  1182. +</PreferenceScreen>
  1183. 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
  1184. new file mode 100755
  1185. --- /dev/null
  1186. +++ b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  1187. @@ -0,0 +1,84 @@
  1188. +/*
  1189. + This file is part of Bromite.
  1190. +
  1191. + Bromite is free software: you can redistribute it and/or modify
  1192. + it under the terms of the GNU General Public License as published by
  1193. + the Free Software Foundation, either version 3 of the License, or
  1194. + (at your option) any later version.
  1195. +
  1196. + Bromite is distributed in the hope that it will be useful,
  1197. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1198. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1199. + GNU General Public License for more details.
  1200. +
  1201. + You should have received a copy of the GNU General Public License
  1202. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1203. +*/
  1204. +
  1205. +package org.chromium.chrome.browser.user_scripts;
  1206. +
  1207. +import android.content.Context;
  1208. +import android.content.Intent;
  1209. +import android.provider.Browser;
  1210. +import android.provider.MediaStore;
  1211. +import android.net.Uri;
  1212. +
  1213. +import org.chromium.base.ContextUtils;
  1214. +import org.chromium.base.ContentUriUtils;
  1215. +import org.chromium.base.IntentUtils;
  1216. +
  1217. +import org.chromium.chrome.browser.IntentHandler;
  1218. +import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  1219. +import org.chromium.components.browser_ui.settings.SettingsLauncher;
  1220. +
  1221. +import org.chromium.components.user_scripts.UserScriptsPreferences;
  1222. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1223. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1224. +
  1225. +public class UserScriptsUtils implements IUserScriptsUtils
  1226. +{
  1227. + private static UserScriptsUtils instance;
  1228. +
  1229. + private UserScriptsUtils() {}
  1230. +
  1231. + public static void Initialize() {
  1232. + instance = new UserScriptsUtils();
  1233. + UserScriptsBridge.registerUtils(instance);
  1234. + }
  1235. +
  1236. + public static UserScriptsUtils getInstance() {
  1237. + return instance;
  1238. + }
  1239. +
  1240. + public boolean openFile(String filePath, String mimeType, String downloadGuid,
  1241. + String originalUrl, String referrer, Uri contentUri) {
  1242. + if (UserScriptsBridge.isEnabled() == false) return false;
  1243. +
  1244. + Context context = ContextUtils.getApplicationContext();
  1245. +
  1246. + if (ContentUriUtils.isContentUri(filePath))
  1247. + filePath = ContentUriUtils.getDisplayName(contentUri, context,
  1248. + MediaStore.MediaColumns.DISPLAY_NAME);
  1249. +
  1250. + if (filePath.toUpperCase().endsWith(".USER.JS") == false) return false;
  1251. +
  1252. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  1253. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  1254. + context, UserScriptsPreferences.class.getName(),
  1255. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  1256. + IntentUtils.safeStartActivity(context, intent);
  1257. +
  1258. + return true;
  1259. + }
  1260. +
  1261. + public void openSourceFile(String scriptKey) {
  1262. + Context context = ContextUtils.getApplicationContext();
  1263. +
  1264. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("chrome://user-scripts/?key=" + scriptKey));
  1265. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1266. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1267. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1268. + intent.setPackage(context.getPackageName());
  1269. + IntentHandler.startChromeLauncherActivityForTrustedIntent(intent);
  1270. + }
  1271. +}
  1272. \ No newline at end of file
  1273. 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
  1274. new file mode 100644
  1275. --- /dev/null
  1276. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1277. @@ -0,0 +1,89 @@
  1278. +// Copyright 2019 The Chromium Authors. All rights reserved.
  1279. +// Use of this source code is governed by a BSD-style license that can be
  1280. +// found in the LICENSE file.
  1281. +
  1282. +package org.chromium.components.user_scripts;
  1283. +
  1284. +import android.annotation.TargetApi;
  1285. +import android.app.Activity;
  1286. +import android.content.Context;
  1287. +import android.content.Intent;
  1288. +import android.content.IntentSender;
  1289. +import android.os.Build;
  1290. +import android.view.View;
  1291. +
  1292. +import androidx.fragment.app.Fragment;
  1293. +
  1294. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  1295. +import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
  1296. +import org.chromium.ui.base.ImmutableWeakReference;
  1297. +import org.chromium.ui.base.IntentRequestTracker;
  1298. +import org.chromium.ui.base.IntentRequestTracker.Delegate;
  1299. +import org.chromium.ui.base.WindowAndroid;
  1300. +
  1301. +import java.lang.ref.WeakReference;
  1302. +
  1303. +/**
  1304. + * Implements intent sending for a fragment based window. This should be created when
  1305. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  1306. + */
  1307. +public class FragmentWindowAndroid extends WindowAndroid {
  1308. + private Fragment mFragment;
  1309. +
  1310. + private static class TrackerDelegateImpl implements Delegate {
  1311. + private final Fragment mFragment;
  1312. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  1313. + // every getActivity call. It is not needed for correctness.
  1314. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  1315. +
  1316. + /**
  1317. + * Create an instance of delegate for the given fragment that will own the
  1318. + * IntentRequestTracker.
  1319. + * @param fragment The fragment that owns the IntentRequestTracker.
  1320. + */
  1321. + private TrackerDelegateImpl(Fragment fragment) {
  1322. + mFragment = fragment;
  1323. + }
  1324. +
  1325. + @Override
  1326. + public boolean startActivityForResult(Intent intent, int requestCode) {
  1327. + mFragment.startActivityForResult(intent, requestCode, null);
  1328. + return true;
  1329. + }
  1330. +
  1331. + @Override
  1332. + public boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  1333. + try {
  1334. + mFragment.startIntentSenderForResult(
  1335. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  1336. + } catch (IntentSender.SendIntentException e) {
  1337. + return false;
  1338. + }
  1339. + return true;
  1340. + }
  1341. +
  1342. + @Override
  1343. + public void finishActivity(int requestCode) {
  1344. + Activity activity = getActivity().get();
  1345. + if (activity == null) return;
  1346. + activity.finishActivity(requestCode);
  1347. + }
  1348. +
  1349. + @Override
  1350. + public final WeakReference<Activity> getActivity() {
  1351. + if (mActivityWeakRefHolder == null
  1352. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1353. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1354. + }
  1355. + return mActivityWeakRefHolder;
  1356. + }
  1357. + }
  1358. +
  1359. + FragmentWindowAndroid(Context context, Fragment fragment) {
  1360. + super(context, IntentRequestTracker.createFromDelegate(new TrackerDelegateImpl(fragment)));
  1361. + mFragment = fragment;
  1362. +
  1363. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  1364. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  1365. + }
  1366. +}
  1367. \ No newline at end of file
  1368. 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
  1369. new file mode 100644
  1370. --- /dev/null
  1371. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1372. @@ -0,0 +1,22 @@
  1373. +/*
  1374. + This file is part of Bromite.
  1375. +
  1376. + Bromite is free software: you can redistribute it and/or modify
  1377. + it under the terms of the GNU General Public License as published by
  1378. + the Free Software Foundation, either version 3 of the License, or
  1379. + (at your option) any later version.
  1380. +
  1381. + Bromite is distributed in the hope that it will be useful,
  1382. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1383. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1384. + GNU General Public License for more details.
  1385. +
  1386. + You should have received a copy of the GNU General Public License
  1387. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1388. +*/
  1389. +
  1390. +package org.chromium.components.user_scripts;
  1391. +
  1392. +public interface IUserScriptsUtils {
  1393. + public void openSourceFile(String scriptKey);
  1394. +}
  1395. \ No newline at end of file
  1396. 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
  1397. new file mode 100644
  1398. --- /dev/null
  1399. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1400. @@ -0,0 +1,37 @@
  1401. +/*
  1402. + This file is part of Bromite.
  1403. +
  1404. + Bromite is free software: you can redistribute it and/or modify
  1405. + it under the terms of the GNU General Public License as published by
  1406. + the Free Software Foundation, either version 3 of the License, or
  1407. + (at your option) any later version.
  1408. +
  1409. + Bromite is distributed in the hope that it will be useful,
  1410. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1411. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1412. + GNU General Public License for more details.
  1413. +
  1414. + You should have received a copy of the GNU General Public License
  1415. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1416. +*/
  1417. +
  1418. +package org.chromium.components.user_scripts;
  1419. +
  1420. +import java.time.LocalDateTime;
  1421. +
  1422. +public class ScriptInfo {
  1423. + public String Key;
  1424. + public String Name;
  1425. + public String Description;
  1426. + public String Version;
  1427. + public String FilePath;
  1428. + public String UrlSource;
  1429. +
  1430. + public boolean Enabled;
  1431. + public LocalDateTime InstallTime;
  1432. +
  1433. + public String ParserError;
  1434. + public boolean ForceDisabled;
  1435. +
  1436. + public ScriptInfo() {}
  1437. +}
  1438. 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
  1439. new file mode 100644
  1440. --- /dev/null
  1441. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1442. @@ -0,0 +1,163 @@
  1443. +/*
  1444. + This file is part of Bromite.
  1445. +
  1446. + Bromite is free software: you can redistribute it and/or modify
  1447. + it under the terms of the GNU General Public License as published by
  1448. + the Free Software Foundation, either version 3 of the License, or
  1449. + (at your option) any later version.
  1450. +
  1451. + Bromite is distributed in the hope that it will be useful,
  1452. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1453. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1454. + GNU General Public License for more details.
  1455. +
  1456. + You should have received a copy of the GNU General Public License
  1457. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1458. +*/
  1459. +
  1460. +package org.chromium.components.user_scripts;
  1461. +
  1462. +import android.content.Context;
  1463. +import android.view.LayoutInflater;
  1464. +import android.view.MotionEvent;
  1465. +import android.view.View;
  1466. +import android.view.ViewGroup;
  1467. +import android.view.accessibility.AccessibilityManager;
  1468. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1469. +import android.widget.ImageView;
  1470. +import android.widget.TextView;
  1471. +import android.widget.Switch;
  1472. +import android.widget.CompoundButton;
  1473. +import android.widget.LinearLayout;
  1474. +
  1475. +import androidx.annotation.DrawableRes;
  1476. +import androidx.annotation.NonNull;
  1477. +import androidx.core.view.ViewCompat;
  1478. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1479. +
  1480. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1481. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1482. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1483. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1484. +import org.chromium.ui.widget.ChromeImageView;
  1485. +
  1486. +import java.util.ArrayList;
  1487. +import java.util.List;
  1488. +
  1489. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1490. +
  1491. + class ItemClickListener {
  1492. + void onScriptOnOff(boolean Enabled) {}
  1493. + void onScriptClicked() {}
  1494. + }
  1495. +
  1496. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1497. + private TextView mTitle;
  1498. + private TextView mDescription;
  1499. + private TextView mVersion;
  1500. + private TextView mFile;
  1501. + private TextView mUrl;
  1502. + private TextView mError;
  1503. + private Switch mSwitch;
  1504. + private ChromeImageView mIcon;
  1505. + private LinearLayout mErrorLayout;
  1506. + private LinearLayout mUrlContainer;
  1507. +
  1508. + private ListMenuButton mMoreButton;
  1509. +
  1510. + private CompoundButton.OnCheckedChangeListener mOnOffListener;
  1511. +
  1512. + ScriptInfoRowViewHolder(View view) {
  1513. + super(view);
  1514. +
  1515. + mSwitch = view.findViewById(R.id.switch_widget);
  1516. + mTitle = view.findViewById(R.id.title);
  1517. + mDescription = view.findViewById(R.id.description);
  1518. + mVersion = view.findViewById(R.id.version);
  1519. + mFile = view.findViewById(R.id.file);
  1520. + mUrl = view.findViewById(R.id.url);
  1521. + mUrlContainer = view.findViewById(R.id.url_container);
  1522. + mError = view.findViewById(R.id.error);
  1523. + mIcon = view.findViewById(R.id.icon);
  1524. + mErrorLayout = view.findViewById(R.id.error_layout);
  1525. +
  1526. + mMoreButton = view.findViewById(R.id.more);
  1527. + }
  1528. +
  1529. + protected void updateScriptInfo(ScriptInfo item) {
  1530. + mSwitch.setOnCheckedChangeListener(null);
  1531. + mSwitch.setChecked(item.Enabled);
  1532. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1533. +
  1534. + mSwitch.setEnabled(true);
  1535. + if (item.ForceDisabled) {
  1536. + mSwitch.setEnabled(false);
  1537. + }
  1538. +
  1539. + mTitle.setText(item.Name);
  1540. + mDescription.setText(item.Description);
  1541. + mVersion.setText(item.Version);
  1542. + mFile.setText(item.Key);
  1543. + mUrl.setText(item.UrlSource);
  1544. + mError.setText(item.ParserError);
  1545. +
  1546. + mUrl.setVisibility(View.VISIBLE);
  1547. + if (item.UrlSource == null || item.UrlSource.isEmpty()) {
  1548. + mUrlContainer.setVisibility(View.GONE);
  1549. + }
  1550. + mErrorLayout.setVisibility(View.VISIBLE);
  1551. + if (item.ParserError == null || item.ParserError.isEmpty()) {
  1552. + mErrorLayout.setVisibility(View.GONE);
  1553. + }
  1554. + }
  1555. +
  1556. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1557. + mMoreButton.setVisibility(View.VISIBLE);
  1558. + mMoreButton.setDelegate(delegate);
  1559. + // Set item row end padding 0 when MenuButton is visible.
  1560. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1561. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1562. + }
  1563. +
  1564. + void setItemListener(@NonNull ItemClickListener listener) {
  1565. + mOnOffListener = (buttonView, isChecked) -> listener.onScriptOnOff(isChecked);
  1566. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1567. + itemView.setOnClickListener(view -> listener.onScriptClicked());
  1568. + }
  1569. + }
  1570. +
  1571. + ScriptListBaseAdapter(Context context) {
  1572. + super(context);
  1573. + }
  1574. +
  1575. + @Override
  1576. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1577. + View row = LayoutInflater.from(viewGroup.getContext())
  1578. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1579. + return new ScriptInfoRowViewHolder(row);
  1580. + }
  1581. +
  1582. + @Override
  1583. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1584. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1585. + }
  1586. +
  1587. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1588. + mElements = new ArrayList<>(values);
  1589. + notifyDataSetChanged();
  1590. + }
  1591. +
  1592. + @Override
  1593. + protected void setOrder(List<ScriptInfo> order) {
  1594. + }
  1595. +
  1596. + @Override
  1597. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1598. + return isPassivelyDraggable(viewHolder);
  1599. + }
  1600. +
  1601. + @Override
  1602. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1603. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1604. + }
  1605. +}
  1606. 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
  1607. new file mode 100644
  1608. --- /dev/null
  1609. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1610. @@ -0,0 +1,171 @@
  1611. +/*
  1612. + This file is part of Bromite.
  1613. +
  1614. + Bromite is free software: you can redistribute it and/or modify
  1615. + it under the terms of the GNU General Public License as published by
  1616. + the Free Software Foundation, either version 3 of the License, or
  1617. + (at your option) any later version.
  1618. +
  1619. + Bromite is distributed in the hope that it will be useful,
  1620. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1621. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1622. + GNU General Public License for more details.
  1623. +
  1624. + You should have received a copy of the GNU General Public License
  1625. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1626. +*/
  1627. +
  1628. +package org.chromium.components.user_scripts;
  1629. +
  1630. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1631. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1632. +
  1633. +import android.content.Context;
  1634. +import android.content.Intent;
  1635. +import android.provider.Browser;
  1636. +import android.net.Uri;
  1637. +import android.util.AttributeSet;
  1638. +import android.widget.TextView;
  1639. +import android.widget.Toast;
  1640. +
  1641. +import androidx.preference.Preference;
  1642. +import androidx.preference.PreferenceViewHolder;
  1643. +import androidx.recyclerview.widget.DividerItemDecoration;
  1644. +import androidx.recyclerview.widget.LinearLayoutManager;
  1645. +import androidx.recyclerview.widget.RecyclerView;
  1646. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1647. +
  1648. +import org.chromium.ui.base.WindowAndroid;
  1649. +import org.chromium.ui.base.ActivityWindowAndroid;
  1650. +
  1651. +import org.chromium.base.ApplicationStatus;
  1652. +import org.chromium.base.ContextUtils;
  1653. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1654. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1655. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1656. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1657. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1658. +
  1659. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1660. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1661. +
  1662. +import java.util.List;
  1663. +
  1664. +public class ScriptListPreference extends Preference {
  1665. + private static class ScriptListAdapter
  1666. + extends ScriptListBaseAdapter {
  1667. + private final Context mContext;
  1668. +
  1669. + ScriptListAdapter(Context context) {
  1670. + super(context);
  1671. + mContext = context;
  1672. + }
  1673. +
  1674. + @Override
  1675. + public void onBindViewHolder(ViewHolder holder, int position) {
  1676. + super.onBindViewHolder(holder, position);
  1677. +
  1678. + final ScriptInfo info = getItemByPosition(position);
  1679. +
  1680. + ModelList menuItems = new ModelList();
  1681. +
  1682. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1683. + menuItems.add(buildMenuListItem(R.string.scripts_view_source, 0, 0,
  1684. + info.ParserError == null || info.ParserError.isEmpty()));
  1685. +
  1686. + ListMenu.Delegate delegate = (model) -> {
  1687. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1688. + if (textId == R.string.remove) {
  1689. + UserScriptsBridge.RemoveScript(info.Key);
  1690. + } else if (textId == R.string.scripts_view_source) {
  1691. + UserScriptsBridge.getUtils().openSourceFile(info.Key);
  1692. + }
  1693. + };
  1694. + ((ScriptInfoRowViewHolder) holder)
  1695. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1696. + ((ScriptInfoRowViewHolder) holder)
  1697. + .setItemListener(new ScriptListBaseAdapter.ItemClickListener() {
  1698. + @Override
  1699. + public void onScriptOnOff(boolean Enabled) {
  1700. + UserScriptsBridge.SetScriptEnabled(info.Key, Enabled);
  1701. + }
  1702. +
  1703. + @Override
  1704. + public void onScriptClicked() {}
  1705. + });
  1706. + }
  1707. +
  1708. + // @Override
  1709. + public void onDataUpdated(boolean enabled) {
  1710. + List<ScriptInfo> list = UserScriptsBridge.getUserScriptItems();
  1711. + if (enabled == false) {
  1712. + for (ScriptInfo script : list) {
  1713. + script.ForceDisabled = true;
  1714. + }
  1715. + }
  1716. + setDisplayedScriptInfo(list);
  1717. + }
  1718. + }
  1719. +
  1720. + private TextView mAddButton;
  1721. + private RecyclerView mRecyclerView;
  1722. + private ScriptListAdapter mAdapter;
  1723. + private FragmentWindowAndroid mWindowAndroid;
  1724. +
  1725. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1726. + super(context, attrs);
  1727. + mAdapter = new ScriptListAdapter(context);
  1728. + }
  1729. +
  1730. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1731. + mWindowAndroid = windowAndroid;
  1732. + }
  1733. +
  1734. + @Override
  1735. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1736. + super.onBindViewHolder(holder);
  1737. +
  1738. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1739. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1740. + TintedDrawable.constructTintedDrawable(
  1741. + getContext(), R.drawable.plus, R.color.default_control_color_active),
  1742. + null, null, null);
  1743. + mAddButton.setOnClickListener(view -> {
  1744. + UserScriptsBridge.SelectAndAddScriptFromFile(mWindowAndroid);
  1745. + });
  1746. +
  1747. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1748. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1749. + mRecyclerView.setLayoutManager(layoutManager);
  1750. + mRecyclerView.addItemDecoration(
  1751. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1752. + mRecyclerView.setEnabled(this.isEnabled());
  1753. + UserScriptsBridge.RegisterLoadCallback(this);
  1754. +
  1755. + // We do not want the RecyclerView to be announced by screen readers every time
  1756. + // the view is bound.
  1757. + if (mRecyclerView.getAdapter() != mAdapter) {
  1758. + mRecyclerView.setAdapter(mAdapter);
  1759. + // Initialize script list.
  1760. + mAdapter.onDataUpdated(this.isEnabled());
  1761. + }
  1762. + }
  1763. +
  1764. + @Override
  1765. + public void setEnabled (boolean enabled) {
  1766. + super.setEnabled(enabled);
  1767. + if (mRecyclerView != null) mRecyclerView.setEnabled(enabled);
  1768. + NotifyScriptsChanged();
  1769. + }
  1770. +
  1771. + public void NotifyScriptsChanged() {
  1772. + mAdapter.onDataUpdated(this.isEnabled());
  1773. + }
  1774. +
  1775. + public void OnUserScriptLoaded(boolean result, String error) {
  1776. + if (result == false) {
  1777. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1778. + toast.show();
  1779. + }
  1780. + }
  1781. +}
  1782. \ No newline at end of file
  1783. 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
  1784. new file mode 100644
  1785. --- /dev/null
  1786. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1787. @@ -0,0 +1,200 @@
  1788. +/*
  1789. + This file is part of Bromite.
  1790. +
  1791. + Bromite is free software: you can redistribute it and/or modify
  1792. + it under the terms of the GNU General Public License as published by
  1793. + the Free Software Foundation, either version 3 of the License, or
  1794. + (at your option) any later version.
  1795. +
  1796. + Bromite is distributed in the hope that it will be useful,
  1797. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1798. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1799. + GNU General Public License for more details.
  1800. +
  1801. + You should have received a copy of the GNU General Public License
  1802. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1803. +*/
  1804. +
  1805. +package org.chromium.components.user_scripts;
  1806. +
  1807. +import java.util.ArrayList;
  1808. +import java.util.List;
  1809. +import java.lang.ref.WeakReference;
  1810. +
  1811. +import org.json.JSONArray;
  1812. +import org.json.JSONException;
  1813. +import org.json.JSONObject;
  1814. +
  1815. +import android.content.Context;
  1816. +import android.content.Intent;
  1817. +import android.net.Uri;
  1818. +import androidx.annotation.Nullable;
  1819. +import android.app.AlertDialog;
  1820. +import android.content.DialogInterface;
  1821. +
  1822. +import org.chromium.base.annotations.CalledByNative;
  1823. +import org.chromium.base.annotations.JNINamespace;
  1824. +import org.chromium.base.annotations.NativeMethods;
  1825. +import org.chromium.base.Log;
  1826. +import org.chromium.ui.base.WindowAndroid;
  1827. +
  1828. +import org.chromium.components.user_scripts.ScriptListPreference;
  1829. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1830. +
  1831. +@JNINamespace("user_scripts")
  1832. +public class UserScriptsBridge {
  1833. + private static final String TAG = "UserScript";
  1834. +
  1835. + static WeakReference<ScriptListPreference> observer;
  1836. +
  1837. + private static IUserScriptsUtils utilInstance;
  1838. +
  1839. + public static void registerUtils(IUserScriptsUtils instance) {
  1840. + utilInstance = instance;
  1841. + }
  1842. +
  1843. + public static IUserScriptsUtils getUtils() {
  1844. + return utilInstance;
  1845. + }
  1846. +
  1847. + public static boolean isEnabled() {
  1848. + return UserScriptsBridgeJni.get().isEnabled();
  1849. + }
  1850. +
  1851. + public static void setEnabled(boolean enabled) {
  1852. + UserScriptsBridgeJni.get().setEnabled(enabled);
  1853. + }
  1854. +
  1855. + public static void RemoveScript(String key) {
  1856. + UserScriptsBridgeJni.get().removeScript(key);
  1857. + }
  1858. +
  1859. + public static void SetScriptEnabled(String key,
  1860. + boolean enabled) {
  1861. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1862. + }
  1863. +
  1864. + public static void Reload() {
  1865. + UserScriptsBridgeJni.get().reload();
  1866. + }
  1867. +
  1868. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1869. + Context context = window.getContext().get();
  1870. +
  1871. + Intent fileSelector = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  1872. + fileSelector.addCategory(Intent.CATEGORY_OPENABLE);
  1873. + fileSelector.setType("*/*");
  1874. + fileSelector.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  1875. +
  1876. + window.showIntent(fileSelector,
  1877. + new WindowAndroid.IntentCallback() {
  1878. + @Override
  1879. + public void onIntentCompleted(int resultCode, Intent data) {
  1880. + if (data == null) return;
  1881. + Uri filePath = data.getData();
  1882. + TryToInstall(context, filePath.toString());
  1883. + }
  1884. + },
  1885. + null);
  1886. + }
  1887. +
  1888. + public static void TryToInstall(Context context, String ScriptFullPath) {
  1889. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1890. + @Override
  1891. + public void onClick(DialogInterface dialog, int which) {
  1892. + switch (which){
  1893. + case DialogInterface.BUTTON_POSITIVE:
  1894. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1895. + break;
  1896. +
  1897. + case DialogInterface.BUTTON_NEGATIVE:
  1898. + break;
  1899. + }
  1900. + }
  1901. + };
  1902. +
  1903. + String message = context.getString(R.string.ask_to_install, ScriptFullPath);
  1904. +
  1905. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1906. + builder.setMessage(message)
  1907. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1908. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1909. + .show();
  1910. + }
  1911. +
  1912. + public static List<ScriptInfo> getUserScriptItems() {
  1913. + List<ScriptInfo> list = new ArrayList<>();
  1914. + try {
  1915. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1916. +
  1917. + JSONObject jsonObject = new JSONObject(json);
  1918. +
  1919. + JSONArray scripts = jsonObject.names();
  1920. + if (scripts != null) {
  1921. + Log.i(TAG, "User Scripts Loaded: %s", json);
  1922. + Log.i(TAG, "Totals scripts: %s", Integer.toString(scripts.length()));
  1923. + for (int i = 0; i < scripts.length(); i++) {
  1924. + String key = (String) scripts.get(i);
  1925. + JSONObject script = jsonObject.getJSONObject(key);
  1926. +
  1927. + ScriptInfo si = new ScriptInfo();
  1928. + si.Key = key;
  1929. + list.add(si);
  1930. +
  1931. + if(script.has("name")) si.Name = script.getString("name");
  1932. + if(script.has("description")) si.Description = script.getString("description");
  1933. + if(script.has("version")) si.Version = script.getString("version");
  1934. + if(script.has("file_path")) si.FilePath = script.getString("file_path");
  1935. + if(script.has("url_source")) si.UrlSource = script.getString("url_source");
  1936. + if(script.has("parser_error")) si.ParserError = script.getString("parser_error");
  1937. + if(script.has("force_disabled")) si.ForceDisabled = script.getBoolean("force_disabled");;
  1938. + si.Enabled = script.getBoolean("enabled");
  1939. + }
  1940. + } else {
  1941. + Log.i(TAG, "User Scripts list empty");
  1942. + }
  1943. + } catch (Exception e) {
  1944. + Log.e(TAG, "User Scripts Load Error", e.toString());
  1945. + }
  1946. + return list;
  1947. + }
  1948. +
  1949. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1950. + UserScriptsBridgeJni.get().registerLoadCallback();
  1951. + observer = new WeakReference<ScriptListPreference>(caller);
  1952. + }
  1953. +
  1954. + @CalledByNative
  1955. + private static void shouldRefreshUserScriptList() {
  1956. + ScriptListPreference reference = observer.get();
  1957. + if (reference != null) {
  1958. + reference.NotifyScriptsChanged();
  1959. + }
  1960. + }
  1961. +
  1962. + @CalledByNative
  1963. + private static void onUserScriptLoaded(boolean result, String error) {
  1964. + ScriptListPreference reference = observer.get();
  1965. + if (reference != null) {
  1966. + reference.OnUserScriptLoaded(result, error);
  1967. + }
  1968. + }
  1969. +
  1970. + @NativeMethods
  1971. + interface Natives {
  1972. + boolean isEnabled();
  1973. + void setEnabled(boolean enabled);
  1974. +
  1975. + String getScriptsInfo();
  1976. +
  1977. + void removeScript(String scriptKey);
  1978. + void setScriptEnabled(String scriptKey, boolean enabled);
  1979. +
  1980. + void reload();
  1981. + void selectAndAddScriptFromFile(WindowAndroid window);
  1982. + void tryToInstall(String scriptFullPath);
  1983. +
  1984. + void registerLoadCallback();
  1985. + }
  1986. +
  1987. +}
  1988. 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
  1989. new file mode 100755
  1990. --- /dev/null
  1991. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  1992. @@ -0,0 +1,116 @@
  1993. +/*
  1994. + This file is part of Bromite.
  1995. +
  1996. + Bromite is free software: you can redistribute it and/or modify
  1997. + it under the terms of the GNU General Public License as published by
  1998. + the Free Software Foundation, either version 3 of the License, or
  1999. + (at your option) any later version.
  2000. +
  2001. + Bromite is distributed in the hope that it will be useful,
  2002. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2003. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2004. + GNU General Public License for more details.
  2005. +
  2006. + You should have received a copy of the GNU General Public License
  2007. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2008. +*/
  2009. +
  2010. +package org.chromium.components.user_scripts;
  2011. +
  2012. +import android.app.Activity;
  2013. +import android.content.Context;
  2014. +import android.content.Intent;
  2015. +import android.os.Bundle;
  2016. +import android.provider.Browser;
  2017. +import android.net.Uri;
  2018. +import android.view.MenuItem;
  2019. +import android.view.View;
  2020. +
  2021. +import androidx.preference.Preference;
  2022. +import androidx.preference.PreferenceFragmentCompat;
  2023. +
  2024. +import org.chromium.base.Log;
  2025. +import org.chromium.ui.base.WindowAndroid;
  2026. +import org.chromium.ui.base.ActivityWindowAndroid;
  2027. +
  2028. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  2029. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  2030. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  2031. +
  2032. +import org.chromium.components.user_scripts.UserScriptsBridge;
  2033. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  2034. +
  2035. +public class UserScriptsPreferences
  2036. + extends PreferenceFragmentCompat
  2037. + implements SettingsUtils.ISupportHelpAndFeedback {
  2038. +
  2039. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  2040. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  2041. +
  2042. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  2043. +
  2044. + private FragmentWindowAndroid mWindowAndroid;
  2045. +
  2046. + @Override
  2047. + public void onDestroy() {
  2048. + if (mWindowAndroid != null) mWindowAndroid.destroy();
  2049. + super.onDestroy();
  2050. + }
  2051. +
  2052. + @Override
  2053. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  2054. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  2055. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  2056. +
  2057. + ChromeSwitchPreference enabledSwitch =
  2058. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  2059. + ScriptListPreference listPreference =
  2060. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  2061. +
  2062. + boolean enabled = UserScriptsBridge.isEnabled();
  2063. + enabledSwitch.setChecked(enabled);
  2064. + listPreference.setEnabled(enabled);
  2065. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  2066. + UserScriptsBridge.setEnabled((boolean) newValue);
  2067. + listPreference.setEnabled((boolean) newValue);
  2068. + return true;
  2069. + });
  2070. +
  2071. + mWindowAndroid = new FragmentWindowAndroid(getContext(), this);
  2072. + listPreference.setWindowAndroid(mWindowAndroid);
  2073. + }
  2074. +
  2075. + @Override
  2076. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  2077. + // handle picker callback from SelectFileDialog
  2078. + mWindowAndroid.getIntentRequestTracker().onActivityResult(requestCode, resultCode, data);
  2079. + }
  2080. +
  2081. + public void onHelpAndFeebackPressed() {
  2082. + Context context = getContext();
  2083. +
  2084. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  2085. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  2086. + // the user presses 'back' button.
  2087. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  2088. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  2089. + intent.setPackage(context.getPackageName());
  2090. + context.startActivity(intent);
  2091. + }
  2092. +
  2093. + public static Bundle createFragmentArgsForInstall(String filePath) {
  2094. + Bundle fragmentArgs = new Bundle();
  2095. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  2096. + return fragmentArgs;
  2097. + }
  2098. +
  2099. + @Override
  2100. + public void onActivityCreated(Bundle savedInstanceState) {
  2101. + super.onActivityCreated(savedInstanceState);
  2102. +
  2103. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  2104. + if (scriptToInstall != null) {
  2105. + UserScriptsBridge.TryToInstall(getContext(), scriptToInstall);
  2106. + }
  2107. + }
  2108. +}
  2109. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  2110. new file mode 100644
  2111. --- /dev/null
  2112. +++ b/components/user_scripts/android/java_sources.gni
  2113. @@ -0,0 +1,18 @@
  2114. +# This file is part of Bromite.
  2115. +
  2116. +# Bromite is free software: you can redistribute it and/or modify
  2117. +# it under the terms of the GNU General Public License as published by
  2118. +# the Free Software Foundation, either version 3 of the License, or
  2119. +# (at your option) any later version.
  2120. +
  2121. +# Bromite is distributed in the hope that it will be useful,
  2122. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2123. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2124. +# GNU General Public License for more details.
  2125. +
  2126. +# You should have received a copy of the GNU General Public License
  2127. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2128. +
  2129. +userscripts_java_sources = [
  2130. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  2131. +]
  2132. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  2133. new file mode 100644
  2134. --- /dev/null
  2135. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  2136. @@ -0,0 +1,173 @@
  2137. +/*
  2138. + This file is part of Bromite.
  2139. +
  2140. + Bromite is free software: you can redistribute it and/or modify
  2141. + it under the terms of the GNU General Public License as published by
  2142. + the Free Software Foundation, either version 3 of the License, or
  2143. + (at your option) any later version.
  2144. +
  2145. + Bromite is distributed in the hope that it will be useful,
  2146. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2147. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2148. + GNU General Public License for more details.
  2149. +
  2150. + You should have received a copy of the GNU General Public License
  2151. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2152. +*/
  2153. +
  2154. +#include <jni.h>
  2155. +#include <algorithm>
  2156. +#include <string>
  2157. +#include <vector>
  2158. +#include <sstream>
  2159. +#include <iterator>
  2160. +
  2161. +#include "base/android/callback_android.h"
  2162. +#include "base/android/jni_android.h"
  2163. +#include "base/android/jni_array.h"
  2164. +#include "base/android/jni_string.h"
  2165. +#include "base/android/scoped_java_ref.h"
  2166. +#include "ui/android/window_android.h"
  2167. +
  2168. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  2169. +#include "../browser/userscripts_browser_client.h"
  2170. +#include "user_scripts_bridge.h"
  2171. +
  2172. +using base::android::AttachCurrentThread;
  2173. +using base::android::ConvertJavaStringToUTF8;
  2174. +using base::android::ConvertUTF16ToJavaString;
  2175. +using base::android::ConvertUTF8ToJavaString;
  2176. +using base::android::JavaParamRef;
  2177. +using base::android::JavaRef;
  2178. +using base::android::ScopedJavaGlobalRef;
  2179. +using base::android::ScopedJavaLocalRef;
  2180. +using content::BrowserContext;
  2181. +
  2182. +namespace {
  2183. +
  2184. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  2185. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  2186. +}
  2187. +
  2188. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  2189. + private:
  2190. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  2191. + content::BrowserContext* browser_context) override {
  2192. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  2193. + }
  2194. +
  2195. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  2196. + bool result, const std::string& error) override {
  2197. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  2198. + result, error);
  2199. + }
  2200. +
  2201. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  2202. +};
  2203. +
  2204. +CallbackObserver* g_userscripts_loader_observer = NULL;
  2205. +
  2206. +}
  2207. +
  2208. +namespace user_scripts {
  2209. +
  2210. +static jboolean JNI_UserScriptsBridge_IsEnabled(
  2211. + JNIEnv* env) {
  2212. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2213. + if (client == NULL) return false;
  2214. + return client->GetPrefs()->IsEnabled();
  2215. +}
  2216. +
  2217. +static void JNI_UserScriptsBridge_SetEnabled(
  2218. + JNIEnv* env,
  2219. + jboolean is_enabled) {
  2220. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2221. + if (client == NULL) return;
  2222. + client->GetPrefs()->SetEnabled(is_enabled);
  2223. + client->GetLoader()->StartLoad();
  2224. +}
  2225. +
  2226. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  2227. + JNIEnv* env) {
  2228. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2229. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  2230. +
  2231. + std::string json = client->GetPrefs()->GetScriptsInfo();
  2232. + return ConvertUTF8ToJavaString(env, json);
  2233. +}
  2234. +
  2235. +static void JNI_UserScriptsBridge_RemoveScript(
  2236. + JNIEnv* env,
  2237. + const JavaParamRef<jstring>& jscript_key) {
  2238. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2239. + if (client == NULL) return;
  2240. +
  2241. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2242. + client->GetLoader()->RemoveScript(script_key);
  2243. +}
  2244. +
  2245. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  2246. + JNIEnv* env,
  2247. + const JavaParamRef<jstring>& jscript_key,
  2248. + jboolean is_enabled) {
  2249. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2250. + if (client == NULL) return;
  2251. +
  2252. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2253. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  2254. +}
  2255. +
  2256. +static void JNI_UserScriptsBridge_Reload(
  2257. + JNIEnv* env) {
  2258. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2259. + if (client == NULL) return;
  2260. +
  2261. + client->GetLoader()->StartLoad();
  2262. + user_scripts::ShouldRefreshUserScriptList(env);
  2263. +}
  2264. +
  2265. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  2266. + JNIEnv* env,
  2267. + const JavaParamRef<jobject>& jwindow_android) {
  2268. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2269. + if (client == NULL) return;
  2270. +
  2271. + client->GetLoader()->SelectAndAddScriptFromFile(
  2272. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  2273. +}
  2274. +
  2275. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  2276. + const JavaParamRef<jstring>& jscript_path) {
  2277. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2278. + if (client == NULL) return;
  2279. +
  2280. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  2281. + base::FilePath path(script_path);
  2282. +
  2283. + client->GetLoader()->TryToInstall(path);
  2284. +}
  2285. +
  2286. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  2287. + JNIEnv* env) {
  2288. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2289. + if (client == NULL) return;
  2290. +
  2291. + if (g_userscripts_loader_observer == NULL) {
  2292. + g_userscripts_loader_observer = new CallbackObserver();
  2293. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  2294. + }
  2295. +}
  2296. +
  2297. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  2298. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  2299. +}
  2300. +
  2301. +static void OnUserScriptLoaded(JNIEnv* env,
  2302. + bool result, const std::string& error) {
  2303. + base::android::ScopedJavaLocalRef<jstring> j_error =
  2304. + base::android::ConvertUTF8ToJavaString(env, error);
  2305. +
  2306. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  2307. +}
  2308. +
  2309. +}
  2310. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  2311. new file mode 100644
  2312. --- /dev/null
  2313. +++ b/components/user_scripts/android/user_scripts_bridge.h
  2314. @@ -0,0 +1,31 @@
  2315. +/*
  2316. + This file is part of Bromite.
  2317. +
  2318. + Bromite is free software: you can redistribute it and/or modify
  2319. + it under the terms of the GNU General Public License as published by
  2320. + the Free Software Foundation, either version 3 of the License, or
  2321. + (at your option) any later version.
  2322. +
  2323. + Bromite is distributed in the hope that it will be useful,
  2324. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2325. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2326. + GNU General Public License for more details.
  2327. +
  2328. + You should have received a copy of the GNU General Public License
  2329. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2330. +*/
  2331. +
  2332. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2333. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2334. +
  2335. +#include <jni.h>
  2336. +
  2337. +namespace user_scripts {
  2338. +
  2339. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  2340. +static void OnUserScriptLoaded(JNIEnv* env,
  2341. + bool result, const std::string& error);
  2342. +
  2343. +} // namespace user_scripts
  2344. +
  2345. +#endif
  2346. \ No newline at end of file
  2347. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  2348. new file mode 100755
  2349. --- /dev/null
  2350. +++ b/components/user_scripts/browser/BUILD.gn
  2351. @@ -0,0 +1,82 @@
  2352. +# This file is part of Bromite.
  2353. +
  2354. +# Bromite is free software: you can redistribute it and/or modify
  2355. +# it under the terms of the GNU General Public License as published by
  2356. +# the Free Software Foundation, either version 3 of the License, or
  2357. +# (at your option) any later version.
  2358. +
  2359. +# Bromite is distributed in the hope that it will be useful,
  2360. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2361. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2362. +# GNU General Public License for more details.
  2363. +
  2364. +# You should have received a copy of the GNU General Public License
  2365. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2366. +
  2367. +import("//build/config/features.gni")
  2368. +import("//tools/grit/grit_rule.gni")
  2369. +
  2370. +group("browser") {
  2371. + public_deps = [
  2372. + "//components/user_scripts/browser:browser_sources",
  2373. + ]
  2374. +}
  2375. +
  2376. +source_set("browser_sources") {
  2377. + visibility = [ "./*" ]
  2378. +
  2379. + sources = [
  2380. + "file_task_runner.cc",
  2381. + "file_task_runner.h",
  2382. + "userscripts_browser_client.cc",
  2383. + "userscripts_browser_client.h",
  2384. + "user_script_loader.cc",
  2385. + "user_script_loader.h",
  2386. + "user_script_prefs.cc",
  2387. + "user_script_prefs.h",
  2388. + "user_script_pref_info.cc",
  2389. + "user_script_pref_info.h",
  2390. + "ui/user_scripts_ui.h",
  2391. + "ui/user_scripts_ui.cc",
  2392. + ]
  2393. +
  2394. + deps = [
  2395. + ":userscripts_browser_resources",
  2396. + "//base:i18n",
  2397. + "//components/keyed_service/content",
  2398. + "//components/keyed_service/core",
  2399. + "//components/pref_registry",
  2400. + "//components/prefs",
  2401. + "//content/public/browser",
  2402. + "//crypto:platform",
  2403. + "//components/user_scripts/common",
  2404. + "//services/device/public/mojom",
  2405. + "//services/preferences/public/cpp",
  2406. + "//services/service_manager/public/cpp",
  2407. + "//third_party/blink/public/common",
  2408. + "//ui/display",
  2409. + ]
  2410. +
  2411. + public_deps = [
  2412. + "//content/public/common",
  2413. + ]
  2414. +
  2415. + configs += [
  2416. + "//build/config:precompiled_headers",
  2417. + "//build/config/compiler:wexit_time_destructors",
  2418. + ]
  2419. +}
  2420. +
  2421. +group("closure_compile") {
  2422. + deps = [ "resources/user-script-ui:closure_compile" ]
  2423. +}
  2424. +
  2425. +grit("userscripts_browser_resources") {
  2426. + source = "resources/browser_resources.grd"
  2427. +
  2428. + output_dir = "$root_gen_dir/chrome"
  2429. + outputs = [
  2430. + "grit/userscripts_browser_resources.h",
  2431. + "userscripts_browser_resources.pak",
  2432. + ]
  2433. +}
  2434. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2435. new file mode 100755
  2436. --- /dev/null
  2437. +++ b/components/user_scripts/browser/file_task_runner.cc
  2438. @@ -0,0 +1,40 @@
  2439. +/*
  2440. + This file is part of Bromite.
  2441. +
  2442. + Bromite is free software: you can redistribute it and/or modify
  2443. + it under the terms of the GNU General Public License as published by
  2444. + the Free Software Foundation, either version 3 of the License, or
  2445. + (at your option) any later version.
  2446. +
  2447. + Bromite is distributed in the hope that it will be useful,
  2448. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2449. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2450. + GNU General Public License for more details.
  2451. +
  2452. + You should have received a copy of the GNU General Public License
  2453. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2454. +*/
  2455. +
  2456. +#include "file_task_runner.h"
  2457. +
  2458. +#include "base/task/sequenced_task_runner.h"
  2459. +#include "base/task/lazy_thread_pool_task_runner.h"
  2460. +#include "base/task/task_traits.h"
  2461. +
  2462. +namespace user_scripts {
  2463. +
  2464. +namespace {
  2465. +
  2466. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2467. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2468. + base::TaskTraits(base::MayBlock(),
  2469. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2470. + base::TaskPriority::USER_VISIBLE));
  2471. +
  2472. +} // namespace
  2473. +
  2474. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2475. + return g_us_task_runner.Get();
  2476. +}
  2477. +
  2478. +} // namespace user_scripts
  2479. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2480. new file mode 100755
  2481. --- /dev/null
  2482. +++ b/components/user_scripts/browser/file_task_runner.h
  2483. @@ -0,0 +1,34 @@
  2484. +/*
  2485. + This file is part of Bromite.
  2486. +
  2487. + Bromite is free software: you can redistribute it and/or modify
  2488. + it under the terms of the GNU General Public License as published by
  2489. + the Free Software Foundation, either version 3 of the License, or
  2490. + (at your option) any later version.
  2491. +
  2492. + Bromite is distributed in the hope that it will be useful,
  2493. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2494. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2495. + GNU General Public License for more details.
  2496. +
  2497. + You should have received a copy of the GNU General Public License
  2498. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2499. +*/
  2500. +
  2501. +#ifndef USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2502. +#define USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2503. +
  2504. +#include "base/memory/ref_counted.h"
  2505. +#include "base/task/task_traits.h"
  2506. +
  2507. +namespace base {
  2508. +class SequencedTaskRunner;
  2509. +}
  2510. +
  2511. +namespace user_scripts {
  2512. +
  2513. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2514. +
  2515. +} // namespace extensions
  2516. +
  2517. +#endif // USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2518. diff --git a/components/user_scripts/browser/resources/browser_resources.grd b/components/user_scripts/browser/resources/browser_resources.grd
  2519. new file mode 100644
  2520. --- /dev/null
  2521. +++ b/components/user_scripts/browser/resources/browser_resources.grd
  2522. @@ -0,0 +1,14 @@
  2523. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  2524. + <outputs>
  2525. + <output filename="grit/userscripts_browser_resources.h" type="rc_header">
  2526. + <emit emit_type='prepend'></emit>
  2527. + </output>
  2528. + <output filename="userscripts_browser_resources.pak" type="data_package" />
  2529. + </outputs>
  2530. + <release seq="1">
  2531. + <includes>
  2532. + <include name="IDR_USER_SCRIPTS_HTML" file="user-script-ui\user-scripts-ui.html" type="BINDATA" />
  2533. + <include name="IDR_USER_SCRIPTS_JS" file="user-script-ui\user-scripts-ui.js" type="BINDATA" />
  2534. + </includes>
  2535. + </release>
  2536. +</grit>
  2537. \ No newline at end of file
  2538. diff --git a/components/user_scripts/browser/resources/user-script-ui/BUILD.gn b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2539. new file mode 100644
  2540. --- /dev/null
  2541. +++ b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2542. @@ -0,0 +1,12 @@
  2543. +import("//third_party/closure_compiler/compile_js.gni")
  2544. +
  2545. +js_type_check("closure_compile") {
  2546. + deps = [ ":view_script_source" ]
  2547. +}
  2548. +
  2549. +js_library("view_script_source") {
  2550. + deps = [
  2551. + "//ui/webui/resources/js:cr.m",
  2552. + "//ui/webui/resources/js:util.m",
  2553. + ]
  2554. +}
  2555. \ No newline at end of file
  2556. 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
  2557. new file mode 100644
  2558. --- /dev/null
  2559. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2560. @@ -0,0 +1,14 @@
  2561. +<!doctype html>
  2562. +<html lang="en">
  2563. +<head>
  2564. + <meta charset="utf-8">
  2565. + <title>Local State Debug Page</title>
  2566. + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  2567. + <script type="module" src="user-scripts-ui.js"></script>
  2568. +</head>
  2569. +<body>
  2570. + <pre id="content">
  2571. + Loading Script Source file...
  2572. + </pre>
  2573. +</body>
  2574. +</html>
  2575. \ No newline at end of file
  2576. 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
  2577. new file mode 100644
  2578. --- /dev/null
  2579. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2580. @@ -0,0 +1,9 @@
  2581. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
  2582. +import {$} from 'chrome://resources/js/util.m.js';
  2583. +
  2584. +document.addEventListener('DOMContentLoaded', function() {
  2585. + const urlParams = new URLSearchParams(window.location.search);
  2586. + sendWithPromise('requestSource', urlParams.get('key')).then(textContent => {
  2587. + $('content').textContent = textContent[0].content;
  2588. + });
  2589. +});
  2590. \ No newline at end of file
  2591. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.cc b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2592. new file mode 100644
  2593. --- /dev/null
  2594. +++ b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2595. @@ -0,0 +1,148 @@
  2596. +/*
  2597. + This file is part of Bromite.
  2598. +
  2599. + Bromite is free software: you can redistribute it and/or modify
  2600. + it under the terms of the GNU General Public License as published by
  2601. + the Free Software Foundation, either version 3 of the License, or
  2602. + (at your option) any later version.
  2603. +
  2604. + Bromite is distributed in the hope that it will be useful,
  2605. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2606. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2607. + GNU General Public License for more details.
  2608. +
  2609. + You should have received a copy of the GNU General Public License
  2610. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2611. +*/
  2612. +
  2613. +
  2614. +#include <memory>
  2615. +
  2616. +#include "base/bind.h"
  2617. +#include "base/json/json_string_value_serializer.h"
  2618. +#include "base/macros.h"
  2619. +#include "base/memory/writable_shared_memory_region.h"
  2620. +#include "base/strings/string_util.h"
  2621. +#include "base/values.h"
  2622. +
  2623. +#include "chrome/browser/browser_process.h"
  2624. +#include "chrome/browser/profiles/profile.h"
  2625. +#include "chrome/common/url_constants.h"
  2626. +#include "chrome/grit/userscripts_browser_resources.h"
  2627. +#include "components/prefs/pref_service.h"
  2628. +#include "content/public/browser/web_ui.h"
  2629. +#include "content/public/browser/web_ui_controller.h"
  2630. +#include "content/public/browser/web_ui_data_source.h"
  2631. +#include "content/public/browser/web_ui_message_handler.h"
  2632. +
  2633. +#include "user_scripts_ui.h"
  2634. +#include "../userscripts_browser_client.h"
  2635. +#include "../../common/user_script.h"
  2636. +
  2637. +namespace {
  2638. +
  2639. +class UserScriptsUIHandler : public content::WebUIMessageHandler {
  2640. + public:
  2641. + UserScriptsUIHandler();
  2642. + ~UserScriptsUIHandler() override;
  2643. +
  2644. + // content::WebUIMessageHandler:
  2645. + void RegisterMessages() override;
  2646. +
  2647. + private:
  2648. + void HandleRequestSource(base::Value::ConstListView args);
  2649. + void OnScriptsLoaded(
  2650. + const std::string callback_id,
  2651. + const std::string script_key,
  2652. + std::unique_ptr<user_scripts::UserScriptList> user_scripts);
  2653. +
  2654. + std::unique_ptr<user_scripts::UserScriptList> loaded_scripts_;
  2655. +
  2656. + base::WeakPtrFactory<UserScriptsUIHandler> weak_factory_{this};
  2657. +
  2658. + DISALLOW_COPY_AND_ASSIGN(UserScriptsUIHandler);
  2659. +};
  2660. +
  2661. +UserScriptsUIHandler::UserScriptsUIHandler()
  2662. + : loaded_scripts_(new user_scripts::UserScriptList()) {
  2663. +}
  2664. +
  2665. +UserScriptsUIHandler::~UserScriptsUIHandler() {
  2666. +}
  2667. +
  2668. +void UserScriptsUIHandler::RegisterMessages() {
  2669. + web_ui()->RegisterMessageCallback(
  2670. + "requestSource",
  2671. + base::BindRepeating(&UserScriptsUIHandler::HandleRequestSource,
  2672. + base::Unretained(this)));
  2673. +}
  2674. +
  2675. +void UserScriptsUIHandler::HandleRequestSource(base::Value::ConstListView args) {
  2676. + AllowJavascript();
  2677. + if (args.size() < 2) return;
  2678. +
  2679. + std::string callback_id = args[0].GetString();
  2680. + std::string script_key = args[1].GetString();
  2681. + if (script_key.empty()) {
  2682. + std::string json = "Missing key value.";
  2683. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2684. + return;
  2685. + }
  2686. +
  2687. + user_scripts::UserScriptsBrowserClient* client = user_scripts::UserScriptsBrowserClient::GetInstance();
  2688. + if (client == NULL) {
  2689. + std::string json = "User scripts disabled.";
  2690. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2691. + } else {
  2692. + std::unique_ptr<user_scripts::UserScriptList> scripts_to_load =
  2693. + std::move(loaded_scripts_);
  2694. + scripts_to_load->clear();
  2695. +
  2696. + client->GetLoader()->LoadScripts(std::move(scripts_to_load),
  2697. + base::BindOnce(
  2698. + &UserScriptsUIHandler::OnScriptsLoaded,
  2699. + weak_factory_.GetWeakPtr(),
  2700. + callback_id, script_key)
  2701. + );
  2702. + }
  2703. +}
  2704. +
  2705. +void UserScriptsUIHandler::OnScriptsLoaded(
  2706. + const std::string callback_id,
  2707. + const std::string script_key,
  2708. + std::unique_ptr<user_scripts::UserScriptList> user_scripts) {
  2709. + loaded_scripts_ = std::move(user_scripts);
  2710. +
  2711. + base::ListValue response;
  2712. + for (const std::unique_ptr<user_scripts::UserScript>& script : *loaded_scripts_) {
  2713. + if (script->key() == script_key) {
  2714. + auto scriptData = std::make_unique<base::DictionaryValue>();
  2715. + for (const std::unique_ptr<user_scripts::UserScript::File>& js_file :
  2716. + script->js_scripts()) {
  2717. + base::StringPiece contents = js_file->GetContent();
  2718. + scriptData->SetString("content", contents.data());
  2719. + }
  2720. + response.Append(std::move(scriptData));
  2721. + }
  2722. + }
  2723. +
  2724. + ResolveJavascriptCallback(base::Value(callback_id), response);
  2725. +}
  2726. +
  2727. +} // namespace
  2728. +
  2729. +namespace user_scripts {
  2730. +
  2731. +UserScriptsUI::UserScriptsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  2732. + content::WebUIDataSource* html_source =
  2733. + content::WebUIDataSource::Create(kChromeUIUserScriptsHost);
  2734. + html_source->SetDefaultResource(IDR_USER_SCRIPTS_HTML);
  2735. + html_source->AddResourcePath("user-scripts-ui.js", IDR_USER_SCRIPTS_JS);
  2736. + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
  2737. + web_ui->AddMessageHandler(std::make_unique<UserScriptsUIHandler>());
  2738. +}
  2739. +
  2740. +UserScriptsUI::~UserScriptsUI() {
  2741. +}
  2742. +
  2743. +}
  2744. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.h b/components/user_scripts/browser/ui/user_scripts_ui.h
  2745. new file mode 100644
  2746. --- /dev/null
  2747. +++ b/components/user_scripts/browser/ui/user_scripts_ui.h
  2748. @@ -0,0 +1,39 @@
  2749. +/*
  2750. + This file is part of Bromite.
  2751. +
  2752. + Bromite is free software: you can redistribute it and/or modify
  2753. + it under the terms of the GNU General Public License as published by
  2754. + the Free Software Foundation, either version 3 of the License, or
  2755. + (at your option) any later version.
  2756. +
  2757. + Bromite is distributed in the hope that it will be useful,
  2758. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2759. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2760. + GNU General Public License for more details.
  2761. +
  2762. + You should have received a copy of the GNU General Public License
  2763. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2764. +*/
  2765. +
  2766. +#ifndef USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2767. +#define USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2768. +
  2769. +#include "base/macros.h"
  2770. +#include "content/public/browser/web_ui_controller.h"
  2771. +
  2772. +namespace user_scripts {
  2773. +
  2774. +const char kChromeUIUserScriptsHost[] = "user-scripts";
  2775. +
  2776. +class UserScriptsUI : public content::WebUIController {
  2777. + public:
  2778. + explicit UserScriptsUI(content::WebUI* web_ui);
  2779. + ~UserScriptsUI() override;
  2780. +
  2781. + private:
  2782. + DISALLOW_COPY_AND_ASSIGN(UserScriptsUI);
  2783. +};
  2784. +
  2785. +}
  2786. +
  2787. +#endif
  2788. \ No newline at end of file
  2789. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2790. new file mode 100755
  2791. --- /dev/null
  2792. +++ b/components/user_scripts/browser/user_script_loader.cc
  2793. @@ -0,0 +1,714 @@
  2794. +/*
  2795. + This file is part of Bromite.
  2796. +
  2797. + Bromite is free software: you can redistribute it and/or modify
  2798. + it under the terms of the GNU General Public License as published by
  2799. + the Free Software Foundation, either version 3 of the License, or
  2800. + (at your option) any later version.
  2801. +
  2802. + Bromite is distributed in the hope that it will be useful,
  2803. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2804. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2805. + GNU General Public License for more details.
  2806. +
  2807. + You should have received a copy of the GNU General Public License
  2808. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2809. +*/
  2810. +
  2811. +#include "user_script_loader.h"
  2812. +
  2813. +#include <stddef.h>
  2814. +
  2815. +#include <set>
  2816. +#include <string>
  2817. +#include <utility>
  2818. +
  2819. +#include "base/bind.h"
  2820. +#include "base/memory/writable_shared_memory_region.h"
  2821. +#include "base/strings/string_util.h"
  2822. +#include "base/strings/strcat.h"
  2823. +#include "base/files/file.h"
  2824. +#include "base/files/file_util.h"
  2825. +#include "base/files/file_enumerator.h"
  2826. +#include "base/i18n/file_util_icu.h"
  2827. +#include "base/path_service.h"
  2828. +#include "base/base_paths_android.h"
  2829. +#include "base/strings/utf_string_conversions.h"
  2830. +#include "base/android/content_uri_utils.h"
  2831. +#include "base/android/jni_android.h"
  2832. +#include "base/task/task_traits.h"
  2833. +#include "base/version.h"
  2834. +
  2835. +#include "crypto/sha2.h"
  2836. +#include "base/base64.h"
  2837. +
  2838. +#include "build/build_config.h"
  2839. +#include "content/public/browser/browser_context.h"
  2840. +#include "content/public/browser/browser_task_traits.h"
  2841. +#include "content/public/browser/browser_thread.h"
  2842. +#include "content/public/browser/notification_service.h"
  2843. +#include "content/public/browser/notification_types.h"
  2844. +#include "content/public/browser/render_process_host.h"
  2845. +#include "ui/shell_dialogs/select_file_dialog.h"
  2846. +#include "content/browser/file_system_access/file_system_chooser.h"
  2847. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2848. +#include "ui/android/window_android.h"
  2849. +
  2850. +#include "../common/user_scripts_features.h"
  2851. +#include "../common/extension_messages.h"
  2852. +#include "file_task_runner.h"
  2853. +#include "user_script_prefs.h"
  2854. +#include "user_script_pref_info.h"
  2855. +#include "../common/host_id.h"
  2856. +
  2857. +using content::BrowserThread;
  2858. +using content::BrowserContext;
  2859. +
  2860. +namespace user_scripts {
  2861. +
  2862. +namespace {
  2863. +
  2864. +static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2865. +static const base::StringPiece kUserScriptEnd("// ==/UserScript==");
  2866. +static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2867. +static const base::StringPiece kNameDeclaration("// @name");
  2868. +static const base::StringPiece kVersionDeclaration("// @version");
  2869. +static const base::StringPiece kDescriptionDeclaration("// @description");
  2870. +static const base::StringPiece kIncludeDeclaration("// @include");
  2871. +static const base::StringPiece kExcludeDeclaration("// @exclude");
  2872. +static const base::StringPiece kMatchDeclaration("// @match");
  2873. +static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2874. +static const base::StringPiece kRunAtDeclaration("// @run-at");
  2875. +static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2876. +static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2877. +static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2878. +static const base::StringPiece kUrlSourceDeclaration("// @url");
  2879. +static const base::StringPiece kUrlHomePageDeclaration("// @homepage");
  2880. +
  2881. +// internal use
  2882. +static const base::StringPiece kParserError("// @error");
  2883. +static const base::StringPiece kForceDisabled("// @disabled");
  2884. +
  2885. +// Helper function to parse greasesmonkey headers
  2886. +bool GetDeclarationValue(const base::StringPiece& line,
  2887. + const base::StringPiece& prefix,
  2888. + std::string* value) {
  2889. + base::StringPiece::size_type index = line.find(prefix);
  2890. + if (index == base::StringPiece::npos)
  2891. + return false;
  2892. +
  2893. + std::string temp(line.data() + index + prefix.length(),
  2894. + line.length() - index - prefix.length());
  2895. +
  2896. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2897. + return false;
  2898. +
  2899. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2900. + return true;
  2901. +}
  2902. +
  2903. +} // namespace
  2904. +
  2905. +// static
  2906. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2907. + std::unique_ptr<UserScript>& script,
  2908. + bool *found_metadata,
  2909. + std::string& error_message) {
  2910. + // http://wiki.greasespot.net/Metadata_block
  2911. + base::StringPiece line;
  2912. + size_t line_start = 0;
  2913. + size_t line_end = line_start;
  2914. + *found_metadata = false;
  2915. +
  2916. + while (line_start < script_text.length()) {
  2917. + line_end = script_text.find('\n', line_start);
  2918. +
  2919. + // Handle the case where there is no trailing newline in the file.
  2920. + if (line_end == std::string::npos)
  2921. + line_end = script_text.length() - 1;
  2922. +
  2923. + line = base::StringPiece(script_text.data() + line_start,
  2924. + line_end - line_start);
  2925. +
  2926. + if (!*found_metadata) {
  2927. + if (base::StartsWith(line, kUserScriptBegin))
  2928. + *found_metadata = true;
  2929. + } else {
  2930. + if (base::StartsWith(line, kUserScriptEnd))
  2931. + break;
  2932. +
  2933. + std::string value;
  2934. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2935. + // We escape some characters that MatchPattern() considers special.
  2936. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2937. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2938. + script->add_glob(value);
  2939. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2940. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2941. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2942. + script->add_exclude_glob(value);
  2943. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2944. + script->set_name_space(value);
  2945. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2946. + script->set_name(value);
  2947. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2948. + base::Version version(value);
  2949. + if (version.IsValid())
  2950. + script->set_version(version.GetString());
  2951. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  2952. + script->set_description(value);
  2953. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  2954. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  2955. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  2956. + error_message = "Invalid UserScript Schema " + value;
  2957. + return false;
  2958. + }
  2959. + script->add_url_pattern(pattern);
  2960. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  2961. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  2962. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  2963. + error_message = "Invalid UserScript Schema " + value;
  2964. + return false;
  2965. + }
  2966. + script->add_exclude_url_pattern(exclude);
  2967. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  2968. + if (value == kRunAtDocumentStartValue)
  2969. + script->set_run_location(UserScript::DOCUMENT_START);
  2970. + else if (value == kRunAtDocumentEndValue)
  2971. + script->set_run_location(UserScript::DOCUMENT_END);
  2972. + else if (value == kRunAtDocumentIdleValue)
  2973. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  2974. + else {
  2975. + error_message = "Invalid RunAtDeclaration " + value;
  2976. + return false;
  2977. + }
  2978. + } else if (GetDeclarationValue(line, kUrlSourceDeclaration, &value) ||
  2979. + GetDeclarationValue(line, kUrlHomePageDeclaration, &value)) {
  2980. + script->set_url_source(value);
  2981. + } else if (GetDeclarationValue(line, kParserError, &value)) {
  2982. + script->set_parser_error(value);
  2983. + } else if (GetDeclarationValue(line, kForceDisabled, &value)) {
  2984. + script->set_force_disabled();
  2985. + }
  2986. +
  2987. + // TODO(aa): Handle more types of metadata.
  2988. + }
  2989. +
  2990. + line_start = line_end + 1;
  2991. + }
  2992. +
  2993. + // If no patterns were specified, default to @include *. This is what
  2994. + // Greasemonkey does.
  2995. + if (script->globs().empty() && script->url_patterns().is_empty())
  2996. + script->add_glob("*");
  2997. +
  2998. + return true;
  2999. +}
  3000. +
  3001. +// static
  3002. +bool LoadUserScriptFromFile(
  3003. + const base::FilePath& user_script_path, const GURL& original_url,
  3004. + std::unique_ptr<UserScript>& script,
  3005. + bool* found_metadata,
  3006. + std::u16string* error) {
  3007. +
  3008. + base::File infile;
  3009. + if (user_script_path.IsContentUri()) {
  3010. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3011. + LOG(INFO) << "UserScriptLoader: path " << user_script_path << " is a content uri";
  3012. +
  3013. + infile = OpenContentUriForRead(user_script_path);
  3014. + } else {
  3015. + infile = base::File(user_script_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  3016. + }
  3017. +
  3018. + if (!infile.IsValid()) {
  3019. + *error = u"Cannot open script source.";
  3020. + return false;
  3021. + }
  3022. +
  3023. + auto length = infile.GetLength();
  3024. + if (length<=0) {
  3025. + *error = u"File is empty.";
  3026. + return false;
  3027. + }
  3028. +
  3029. + auto buffer = std::vector<char>(length);
  3030. + int bytes_read = infile.Read(0, buffer.data(), length);
  3031. + if (bytes_read == -1) {
  3032. + *error = u"Could not read source file.";
  3033. + return false;
  3034. + }
  3035. +
  3036. + std::string content(buffer.begin(), buffer.end());
  3037. + if (!base::IsStringUTF8(content)) {
  3038. + *error = u"User script must be UTF8 encoded.";
  3039. + return false;
  3040. + }
  3041. +
  3042. + std::string detailed_error;
  3043. + bool parseResult = UserScriptLoader::ParseMetadataHeader(content, script,
  3044. + found_metadata, detailed_error);
  3045. + if (parseResult == false || *found_metadata == false) {
  3046. + std::u16string detailed_error16;
  3047. + base::UTF8ToUTF16(detailed_error.c_str(), detailed_error.length(), &detailed_error16);
  3048. + *error = base::StrCat({u"Invalid script header. ", detailed_error16});
  3049. + return false;
  3050. + }
  3051. +
  3052. + script->set_name(user_script_path.BaseName().value());
  3053. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  3054. +
  3055. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  3056. + file->set_content(content);
  3057. + file->set_url(GURL(base::StrCat({"https://userscripts/file/", script->name(), ".js"})));
  3058. +
  3059. + // create SHA256 of file
  3060. + char raw[crypto::kSHA256Length] = {0};
  3061. + std::string key;
  3062. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  3063. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  3064. + file->set_key(key);
  3065. +
  3066. + script->js_scripts().push_back(std::move(file));
  3067. +
  3068. + // add into key the filename
  3069. + // this value is used in ui to discriminate scripts
  3070. + script->set_key(user_script_path.BaseName().value());
  3071. + return true;
  3072. +}
  3073. +
  3074. +// static
  3075. +bool GetOrCreatePath(base::FilePath& path) {
  3076. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  3077. + path = path.AppendASCII("userscripts");
  3078. +
  3079. + // create snippets directory if not exists
  3080. + if (!base::PathExists(path)) {
  3081. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  3082. + base::File::Error error = base::File::FILE_OK;
  3083. + if (!base::CreateDirectoryAndGetError(path, &error)) {
  3084. + LOG(ERROR) <<
  3085. + "UserScriptLoader: failed to create directory: " << path
  3086. + << " with error code " << error;
  3087. + return false;
  3088. + }
  3089. + }
  3090. + return true;
  3091. +}
  3092. +
  3093. +// static
  3094. +void LoadUserScripts(UserScriptList* user_scripts_list) {
  3095. + base::FilePath path;
  3096. + if (GetOrCreatePath(path) == false) return;
  3097. +
  3098. + // enumerate all files from script path
  3099. + // we accept all files, but we check if it's a real
  3100. + // userscript
  3101. + base::FileEnumerator dir_enum(
  3102. + path,
  3103. + /*recursive=*/false, base::FileEnumerator::FILES);
  3104. + base::FilePath full_name;
  3105. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  3106. + std::unique_ptr<UserScript> userscript(new UserScript());
  3107. + userscript->set_id(UserScript::GenerateUserScriptID());
  3108. + userscript->set_host_id(HostID(HostID::HostType::EXTENSIONS,
  3109. + "_" + base::NumberToString(userscript->id())));
  3110. +
  3111. + std::u16string error;
  3112. + bool found_metadata;
  3113. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &found_metadata, &error)) {
  3114. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3115. + LOG(INFO) << "UserScriptLoader: Found user script " << userscript->name() <<
  3116. + "-" << userscript->version() <<
  3117. + "-" << userscript->description();
  3118. +
  3119. + userscript->set_file_path(full_name.AsUTF8Unsafe());
  3120. + user_scripts_list->push_back(std::move(userscript));
  3121. + } else {
  3122. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3123. + }
  3124. + }
  3125. +}
  3126. +
  3127. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  3128. + UserScriptsPrefs* prefs)
  3129. + : loaded_scripts_(new UserScriptList()),
  3130. + ready_(false),
  3131. + browser_context_(browser_context),
  3132. + prefs_(prefs) {}
  3133. +
  3134. +UserScriptLoader::~UserScriptLoader() {
  3135. + for (auto& observer : observers_)
  3136. + observer.OnUserScriptLoaderDestroyed(this);
  3137. +}
  3138. +
  3139. +void UserScriptLoader::OnRenderProcessHostCreated(
  3140. + content::RenderProcessHost* process_host) {
  3141. + if (initial_load_complete()) {
  3142. + SendUpdate(process_host, shared_memory_);
  3143. + }
  3144. +}
  3145. +
  3146. +void UserScriptLoader::SetReady(bool ready) {
  3147. + bool was_ready = ready_;
  3148. + ready_ = ready;
  3149. + if (ready_ && !was_ready)
  3150. + AttemptLoad();
  3151. +}
  3152. +
  3153. +void UserScriptLoader::AttemptLoad() {
  3154. + int tryOut = prefs_->GetCurrentStartupTryout();
  3155. + if (tryOut >= 3) {
  3156. + LOG(INFO) << "UserScriptLoader: Possible crash detected. UserScript disabled";
  3157. + prefs_->SetEnabled(false);
  3158. + } else {
  3159. + prefs_->StartupTryout(tryOut+1);
  3160. + StartLoad();
  3161. + }
  3162. +}
  3163. +
  3164. +void UserScriptLoader::StartLoad() {
  3165. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3166. +
  3167. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3168. + LOG(INFO) << "UserScriptLoader: StartLoad";
  3169. +
  3170. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  3171. + // the scripts aren't currently ready.
  3172. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  3173. + scripts_to_load->clear();
  3174. +
  3175. + if (prefs_->IsEnabled()) {
  3176. + LoadScripts(std::move(scripts_to_load),
  3177. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  3178. + weak_factory_.GetWeakPtr()));
  3179. + } else {
  3180. + OnScriptsLoaded(std::move(scripts_to_load));
  3181. + }
  3182. +}
  3183. +
  3184. +// static
  3185. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  3186. + const UserScriptList& scripts) {
  3187. + base::Pickle pickle;
  3188. + pickle.WriteUInt32(scripts.size());
  3189. + for (const std::unique_ptr<UserScript>& script : scripts) {
  3190. + // TODO(aa): This can be replaced by sending content script metadata to
  3191. + // renderers along with other extension data in ExtensionMsg_Loaded.
  3192. + // See crbug.com/70516.
  3193. + script->Pickle(&pickle);
  3194. + // Write scripts as 'data' so that we can read it out in the slave without
  3195. + // allocating a new string.
  3196. + for (const std::unique_ptr<UserScript::File>& js_file :
  3197. + script->js_scripts()) {
  3198. + base::StringPiece contents = js_file->GetContent();
  3199. + pickle.WriteData(contents.data(), contents.length());
  3200. + }
  3201. + for (const std::unique_ptr<UserScript::File>& css_file :
  3202. + script->css_scripts()) {
  3203. + base::StringPiece contents = css_file->GetContent();
  3204. + pickle.WriteData(contents.data(), contents.length());
  3205. + }
  3206. + }
  3207. +
  3208. + // Create the shared memory object.
  3209. + base::MappedReadOnlyRegion shared_memory =
  3210. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  3211. + if (!shared_memory.IsValid())
  3212. + return {};
  3213. +
  3214. + // Copy the pickle to shared memory.
  3215. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  3216. + return std::move(shared_memory.region);
  3217. +}
  3218. +
  3219. +void UserScriptLoader::AddObserver(Observer* observer) {
  3220. + observers_.AddObserver(observer);
  3221. +}
  3222. +
  3223. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  3224. + observers_.RemoveObserver(observer);
  3225. +}
  3226. +
  3227. +void UserScriptLoader::OnScriptsLoaded(
  3228. + std::unique_ptr<UserScriptList> user_scripts) {
  3229. +
  3230. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3231. + LOG(INFO) << "UserScriptLoader: OnScriptsLoaded";
  3232. +
  3233. + // Check user preferences for loaded user scripts
  3234. + prefs_->CompareWithPrefs(*user_scripts);
  3235. + loaded_scripts_ = std::move(user_scripts);
  3236. +
  3237. + base::ReadOnlySharedMemoryRegion shared_memory;
  3238. + shared_memory =
  3239. + UserScriptLoader::Serialize(*loaded_scripts_);
  3240. +
  3241. + if (!shared_memory.IsValid()) {
  3242. + // This can happen if we run out of file descriptors. In that case, we
  3243. + // have a choice between silently omitting all user scripts for new tabs,
  3244. + // by nulling out shared_memory_, or only silently omitting new ones by
  3245. + // leaving the existing object in place. The second seems less bad, even
  3246. + // though it removes the possibility that freeing the shared memory block
  3247. + // would open up enough FDs for long enough for a retry to succeed.
  3248. +
  3249. + // Pretend the extension change didn't happen.
  3250. + return;
  3251. + }
  3252. +
  3253. + // We've got scripts ready to go.
  3254. + shared_memory_ = std::move(shared_memory);
  3255. +
  3256. + for (content::RenderProcessHost::iterator i(
  3257. + content::RenderProcessHost::AllHostsIterator());
  3258. + !i.IsAtEnd(); i.Advance()) {
  3259. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  3260. + }
  3261. +
  3262. + // DCHECK(false); trying crash
  3263. + prefs_->StartupTryout(0);
  3264. +
  3265. + for (auto& observer : observers_)
  3266. + observer.OnScriptsLoaded(this, browser_context_);
  3267. +}
  3268. +
  3269. +void UserScriptLoader::SendUpdate(
  3270. + content::RenderProcessHost* process,
  3271. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  3272. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3273. + LOG(INFO) << "UserScriptLoader: SendUpdate";
  3274. +
  3275. + // If the process is being started asynchronously, early return. We'll end up
  3276. + // calling InitUserScripts when it's created which will call this again.
  3277. + base::ProcessHandle handle = process->GetProcess().Handle();
  3278. + if (!handle)
  3279. + return;
  3280. +
  3281. + base::ReadOnlySharedMemoryRegion region_for_process =
  3282. + shared_memory.Duplicate();
  3283. + if (!region_for_process.IsValid())
  3284. + return;
  3285. +
  3286. + process->Send(new ExtensionMsg_UpdateUserScripts(
  3287. + std::move(region_for_process)));
  3288. +}
  3289. +
  3290. +void LoadScriptsOnFileTaskRunner(
  3291. + std::unique_ptr<UserScriptList> user_scripts,
  3292. + UserScriptLoader::LoadScriptsCallback callback) {
  3293. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3294. + DCHECK(user_scripts.get());
  3295. +
  3296. + // load user scripts from path
  3297. + LoadUserScripts(user_scripts.get());
  3298. +
  3299. + // Explicit priority to prevent unwanted task priority inheritance.
  3300. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3301. + ->PostTask(FROM_HERE,
  3302. + base::BindOnce(std::move(callback), std::move(user_scripts)));
  3303. +}
  3304. +
  3305. +void UserScriptLoader::LoadScripts(
  3306. + std::unique_ptr<UserScriptList> user_scripts,
  3307. + LoadScriptsCallback callback) {
  3308. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  3309. +
  3310. + GetUserScriptsFileTaskRunner()->PostTask(
  3311. + FROM_HERE,
  3312. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  3313. + std::move(callback)));
  3314. +}
  3315. +
  3316. +void RemoveScriptsOnFileTaskRunner(
  3317. + const std::string& script_id,
  3318. + UserScriptLoader::RemoveScriptCallback callback) {
  3319. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3320. +
  3321. + base::FilePath path;
  3322. + if (GetOrCreatePath(path)) {
  3323. + base::FilePath file = path.Append(script_id);
  3324. + if (base::DeleteFile(file) == false) {
  3325. + LOG(ERROR) <<
  3326. + "ERROR: failed to delete file : " << path;
  3327. + }
  3328. + }
  3329. +
  3330. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3331. + ->PostTask(FROM_HERE,
  3332. + base::BindOnce(std::move(callback)));
  3333. +}
  3334. +
  3335. +void UserScriptLoader::OnScriptRemoved() {
  3336. + StartLoad();
  3337. +}
  3338. +
  3339. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  3340. + if (!prefs_->IsEnabled()) return;
  3341. + prefs_->RemoveScriptFromPrefs(script_id);
  3342. +
  3343. + GetUserScriptsFileTaskRunner()->PostTask(
  3344. + FROM_HERE,
  3345. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  3346. + std::move(script_id),
  3347. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  3348. + weak_factory_.GetWeakPtr())));
  3349. +}
  3350. +
  3351. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3352. + if (!prefs_->IsEnabled()) return;
  3353. + prefs_->SetScriptEnabled(script_id, is_enabled);
  3354. + StartLoad();
  3355. +}
  3356. +
  3357. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  3358. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3359. +
  3360. + if (!prefs_->IsEnabled()) return;
  3361. +
  3362. + dialog_ = ui::SelectFileDialog::Create(
  3363. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  3364. +
  3365. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  3366. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  3367. + allowed_file_info.allowed_paths =
  3368. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  3369. + base::FilePath suggested_name;
  3370. +
  3371. + std::vector<std::u16string> types;
  3372. + types.push_back(u"*/*"); /*= java SelectFileDialog.ALL_TYPES*/
  3373. + std::pair<std::vector<std::u16string>, bool> accept_types = std::make_pair(
  3374. + types, false /*use_media_capture*/);
  3375. +
  3376. + dialog_->SelectFile(
  3377. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  3378. + std::u16string() /* dialog title*/, suggested_name, &allowed_file_info,
  3379. + 0 /* file type index */, std::string() /* default file extension */,
  3380. + nativeWindow,
  3381. + &accept_types /* params */);
  3382. +}
  3383. +
  3384. +
  3385. +void LoadScriptFromPathOnFileTaskRunner(
  3386. + const base::FilePath& path,
  3387. + const std::string& display_name,
  3388. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  3389. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3390. +
  3391. + std::unique_ptr<UserScript> userscript(new UserScript());
  3392. + std::u16string error;
  3393. + bool found_metadata = false;
  3394. + bool loaded = LoadUserScriptFromFile(path, GURL(), userscript, &found_metadata, &error);
  3395. +
  3396. + bool result = loaded;
  3397. + if (result || found_metadata) {
  3398. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3399. + LOG(INFO) << "UserScriptLoader: found " << userscript->name() <<
  3400. + "-" << userscript->version() <<
  3401. + "-" << userscript->description();
  3402. + base::FilePath destination;
  3403. + if (GetOrCreatePath(destination) == false) {
  3404. + error = u"Cannot create destination.";
  3405. + } else {
  3406. + // we need an unique file name
  3407. + if (display_name.empty() == false) {
  3408. + userscript->set_key(display_name);
  3409. + }
  3410. +
  3411. + // filename is original filename or display_name
  3412. + std::string file_name(userscript->key());
  3413. + base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
  3414. + destination = destination.Append(file_name);
  3415. +
  3416. + if (destination.ReferencesParent()) {
  3417. + error = u"Invalid file name.";
  3418. + result = false;
  3419. + } else if (base::PathExists(destination)) {
  3420. + error = u"User script already loaded.";
  3421. + result = false;
  3422. + } else {
  3423. + if (loaded) {
  3424. + // if is a correct userscript, copy it
  3425. + result = base::CopyFile(path, destination);
  3426. + if (result == false) {
  3427. + error = u"Copy error.";
  3428. + }
  3429. + } else {
  3430. + // else, there is a parser error
  3431. + // write minimal values and the error string, so UI can show it
  3432. + std::string combined_string = base::StrCat({
  3433. + kUserScriptBegin, "\n",
  3434. + kNamespaceDeclaration, " ", userscript->name_space(), "\n",
  3435. + kNameDeclaration, " ", userscript->name(), "\n",
  3436. + kVersionDeclaration, " ", userscript->version(), "\n",
  3437. + kDescriptionDeclaration, " ", userscript->description(), "\n",
  3438. + kUrlSourceDeclaration, " ", userscript->url_source(), "\n",
  3439. + kParserError, " ", base::UTF16ToASCII(error), "\n",
  3440. + kForceDisabled, " true\n",
  3441. + kUserScriptEnd, "\n"
  3442. + });
  3443. +
  3444. + if (!base::WriteFile(destination, combined_string)) {
  3445. + error = u"Cannot write.";
  3446. + result = false;
  3447. + }
  3448. + }
  3449. + }
  3450. + }
  3451. + }
  3452. +
  3453. + if (!error.empty()) {
  3454. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3455. + }
  3456. +
  3457. + // return to callback with eventually the error
  3458. + const std::string string_error = base::UTF16ToASCII(error);
  3459. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3460. + ->PostTask(FROM_HERE,
  3461. + base::BindOnce(std::move(callback), result,
  3462. + std::move(string_error)));
  3463. +}
  3464. +
  3465. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  3466. + if (!prefs_->IsEnabled()) return;
  3467. +
  3468. + std::u16string file_display_name;
  3469. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  3470. +
  3471. + std::string display_name = script_path.BaseName().value();
  3472. + if (base::IsStringASCII(file_display_name))
  3473. + display_name = base::UTF16ToASCII(file_display_name);
  3474. +
  3475. + GetUserScriptsFileTaskRunner()->PostTask(
  3476. + FROM_HERE,
  3477. + base::BindOnce(
  3478. + &LoadScriptFromPathOnFileTaskRunner,
  3479. + script_path, display_name,
  3480. + base::BindOnce(
  3481. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  3482. + weak_factory_.GetWeakPtr()
  3483. + )
  3484. + ));
  3485. +}
  3486. +
  3487. +void UserScriptLoader::FileSelected(
  3488. + const base::FilePath& path, int index, void* params) {
  3489. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3490. + LOG(INFO) << "UserScriptLoader: FileSelected " << path;
  3491. +
  3492. + UserScriptLoader::TryToInstall(path);
  3493. +}
  3494. +
  3495. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  3496. + bool result, const std::string& error) {
  3497. + for (auto& observer : observers_)
  3498. + observer.OnUserScriptLoaded(this, result, error);
  3499. +
  3500. + StartLoad();
  3501. +}
  3502. +
  3503. +void UserScriptLoader::FileSelectionCanceled(
  3504. + void* params) {
  3505. +}
  3506. +
  3507. +} // namespace extensions
  3508. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  3509. new file mode 100755
  3510. --- /dev/null
  3511. +++ b/components/user_scripts/browser/user_script_loader.h
  3512. @@ -0,0 +1,170 @@
  3513. +/*
  3514. + This file is part of Bromite.
  3515. +
  3516. + Bromite is free software: you can redistribute it and/or modify
  3517. + it under the terms of the GNU General Public License as published by
  3518. + the Free Software Foundation, either version 3 of the License, or
  3519. + (at your option) any later version.
  3520. +
  3521. + Bromite is distributed in the hope that it will be useful,
  3522. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3523. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3524. + GNU General Public License for more details.
  3525. +
  3526. + You should have received a copy of the GNU General Public License
  3527. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3528. +*/
  3529. +
  3530. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3531. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3532. +
  3533. +#include <map>
  3534. +#include <memory>
  3535. +#include <set>
  3536. +
  3537. +#include "base/callback_forward.h"
  3538. +#include "base/compiler_specific.h"
  3539. +#include "base/macros.h"
  3540. +#include "base/memory/read_only_shared_memory_region.h"
  3541. +#include "base/memory/weak_ptr.h"
  3542. +#include "base/observer_list.h"
  3543. +#include "content/public/browser/render_process_host_creation_observer.h"
  3544. +#include "ui/shell_dialogs/select_file_dialog.h"
  3545. +#include "content/browser/file_system_access/file_system_chooser.h"
  3546. +#include "ui/android/window_android.h"
  3547. +
  3548. +#include "../common/host_id.h"
  3549. +#include "../common/user_script.h"
  3550. +#include "user_script_prefs.h"
  3551. +
  3552. +namespace base {
  3553. +class ReadOnlySharedMemoryRegion;
  3554. +}
  3555. +
  3556. +namespace content {
  3557. +class BrowserContext;
  3558. +class RenderProcessHost;
  3559. +}
  3560. +
  3561. +namespace user_scripts {
  3562. +
  3563. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  3564. +// new shared memory region when the set of scripts changes. Also notifies
  3565. +// renderers of new shared memory region when new renderers appear, or when
  3566. +// script reloading completes. Script loading lives on the file thread.
  3567. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  3568. + public ui::SelectFileDialog::Listener {
  3569. + public:
  3570. + using LoadScriptsCallback =
  3571. + base::OnceCallback<void(std::unique_ptr<UserScriptList>)>;
  3572. + using LoadSingleScriptCallback =
  3573. + base::OnceCallback<void(bool result, const std::string& error)>;
  3574. +
  3575. + using RemoveScriptCallback =
  3576. + base::OnceCallback<void()>;
  3577. + class Observer {
  3578. + public:
  3579. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  3580. + content::BrowserContext* browser_context) = 0;
  3581. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  3582. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  3583. + bool result, const std::string& error) = 0;
  3584. + };
  3585. +
  3586. + // Parses the includes out of |script| and returns them in |includes|.
  3587. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  3588. + std::unique_ptr<UserScript>& script,
  3589. + bool *found_metadata,
  3590. + std::string& error_message);
  3591. +
  3592. + UserScriptLoader(content::BrowserContext* browser_context,
  3593. + UserScriptsPrefs* prefs);
  3594. + //const HostID& host_id);
  3595. + ~UserScriptLoader() override;
  3596. +
  3597. + // Initiates procedure to start loading scripts on the file thread.
  3598. + void StartLoad();
  3599. +
  3600. + // Returns true if we have any scripts ready.
  3601. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  3602. +
  3603. + // Pickle user scripts and return pointer to the shared memory.
  3604. + static base::ReadOnlySharedMemoryRegion Serialize(
  3605. + const user_scripts::UserScriptList& scripts);
  3606. +
  3607. + // Adds or removes observers.
  3608. + void AddObserver(Observer* observer);
  3609. + void RemoveObserver(Observer* observer);
  3610. +
  3611. + // Sets the flag if the initial set of hosts has finished loading; if it's
  3612. + // set to be true, calls AttempLoad() to bootstrap.
  3613. + void SetReady(bool ready);
  3614. +
  3615. + void RemoveScript(const std::string& script_id);
  3616. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3617. +
  3618. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  3619. + void TryToInstall(const base::FilePath& script_path);
  3620. +
  3621. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  3622. + LoadScriptsCallback callback);
  3623. +
  3624. + protected:
  3625. + content::BrowserContext* browser_context() const { return browser_context_; }
  3626. +
  3627. + UserScriptsPrefs* prefs() const { return prefs_; }
  3628. +
  3629. + private:
  3630. + void OnRenderProcessHostCreated(
  3631. + content::RenderProcessHost* process_host) override;
  3632. +
  3633. + // Attempts to initiate a load.
  3634. + void AttemptLoad();
  3635. +
  3636. + // Called once we have finished loading the scripts on the file thread.
  3637. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts);
  3638. +
  3639. + // Sends the renderer process a new set of user scripts. If
  3640. + // |changed_hosts| is not empty, this signals that only the scripts from
  3641. + // those hosts should be updated. Otherwise, all hosts will be
  3642. + // updated.
  3643. + void SendUpdate(content::RenderProcessHost* process,
  3644. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  3645. +
  3646. + // Contains the scripts that were found the last time scripts were updated.
  3647. + base::ReadOnlySharedMemoryRegion shared_memory_;
  3648. +
  3649. + // List of scripts that are currently loaded. This is null when a load is in
  3650. + // progress.
  3651. + std::unique_ptr<UserScriptList> loaded_scripts_;
  3652. +
  3653. + // If the initial set of hosts has finished loading.
  3654. + bool ready_;
  3655. +
  3656. + // The browser_context for which the scripts managed here are installed.
  3657. + content::BrowserContext* browser_context_;
  3658. +
  3659. + // Manage load and store from preferences
  3660. + UserScriptsPrefs* prefs_;
  3661. +
  3662. + // The associated observers.
  3663. + base::ObserverList<Observer>::Unchecked observers_;
  3664. +
  3665. + void OnScriptRemoved();
  3666. +
  3667. + // Manage file dialog requests
  3668. + scoped_refptr<ui::SelectFileDialog> dialog_;
  3669. + void FileSelected(const base::FilePath& path,
  3670. + int index, void* params) override;
  3671. + void FileSelectionCanceled(void* params) override;
  3672. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  3673. + bool result, const std::string& error );
  3674. +
  3675. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  3676. +
  3677. + DISALLOW_COPY_AND_ASSIGN(UserScriptLoader);
  3678. +};
  3679. +
  3680. +} // namespace extensions
  3681. +
  3682. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3683. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  3684. new file mode 100644
  3685. --- /dev/null
  3686. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  3687. @@ -0,0 +1,34 @@
  3688. +/*
  3689. + This file is part of Bromite.
  3690. +
  3691. + Bromite is free software: you can redistribute it and/or modify
  3692. + it under the terms of the GNU General Public License as published by
  3693. + the Free Software Foundation, either version 3 of the License, or
  3694. + (at your option) any later version.
  3695. +
  3696. + Bromite is distributed in the hope that it will be useful,
  3697. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3698. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3699. + GNU General Public License for more details.
  3700. +
  3701. + You should have received a copy of the GNU General Public License
  3702. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3703. +*/
  3704. +
  3705. +#include "user_script_pref_info.h"
  3706. +
  3707. +namespace user_scripts {
  3708. +
  3709. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  3710. + const std::string& description,
  3711. + const base::Time& install_time,
  3712. + bool enabled)
  3713. + : install_time(install_time),
  3714. + enabled(enabled),
  3715. + name_(name),
  3716. + description_(description) {}
  3717. +
  3718. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  3719. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  3720. +
  3721. +}
  3722. \ No newline at end of file
  3723. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3724. new file mode 100644
  3725. --- /dev/null
  3726. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3727. @@ -0,0 +1,72 @@
  3728. +/*
  3729. + This file is part of Bromite.
  3730. +
  3731. + Bromite is free software: you can redistribute it and/or modify
  3732. + it under the terms of the GNU General Public License as published by
  3733. + the Free Software Foundation, either version 3 of the License, or
  3734. + (at your option) any later version.
  3735. +
  3736. + Bromite is distributed in the hope that it will be useful,
  3737. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3738. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3739. + GNU General Public License for more details.
  3740. +
  3741. + You should have received a copy of the GNU General Public License
  3742. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3743. +*/
  3744. +
  3745. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3746. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3747. +
  3748. +#include "base/values.h"
  3749. +#include "base/time/time.h"
  3750. +#include "components/keyed_service/core/keyed_service.h"
  3751. +
  3752. +namespace user_scripts {
  3753. +
  3754. +class UserScriptsListPrefs : public KeyedService {
  3755. + public:
  3756. + struct ScriptInfo {
  3757. + ScriptInfo(const std::string& name,
  3758. + const std::string& description,
  3759. + const base::Time& install_time,
  3760. + bool enabled);
  3761. + ScriptInfo(const ScriptInfo& other);
  3762. + ~ScriptInfo();
  3763. +
  3764. + const std::string& name() const { return name_; }
  3765. + void set_name(const std::string& name) { name_ = name; }
  3766. +
  3767. + const std::string& description() const { return description_; }
  3768. + void set_description(const std::string& description) { description_ = description; }
  3769. +
  3770. + const std::string& version() const { return version_; }
  3771. + void set_version(const std::string& version) { version_ = version; }
  3772. +
  3773. + const std::string& file_path() const { return file_path_; }
  3774. + void set_file_path(const std::string& file_path) { file_path_ = file_path; }
  3775. +
  3776. + const std::string& url_source() const { return url_source_; }
  3777. + void set_url_source(const std::string& url_source) { url_source_ = url_source; }
  3778. +
  3779. + const std::string& parser_error() const { return parser_error_; }
  3780. + void set_parser_error(const std::string& parser_error) { parser_error_ = parser_error; }
  3781. +
  3782. + base::Time install_time;
  3783. + bool enabled;
  3784. +
  3785. + bool force_disabled;
  3786. +
  3787. + private:
  3788. + std::string name_;
  3789. + std::string description_;
  3790. + std::string version_;
  3791. + std::string file_path_;
  3792. + std::string url_source_;
  3793. + std::string parser_error_;
  3794. + };
  3795. +};
  3796. +
  3797. +}
  3798. +
  3799. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3800. \ No newline at end of file
  3801. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3802. new file mode 100644
  3803. --- /dev/null
  3804. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3805. @@ -0,0 +1,276 @@
  3806. +/*
  3807. + This file is part of Bromite.
  3808. +
  3809. + Bromite is free software: you can redistribute it and/or modify
  3810. + it under the terms of the GNU General Public License as published by
  3811. + the Free Software Foundation, either version 3 of the License, or
  3812. + (at your option) any later version.
  3813. +
  3814. + Bromite is distributed in the hope that it will be useful,
  3815. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3816. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3817. + GNU General Public License for more details.
  3818. +
  3819. + You should have received a copy of the GNU General Public License
  3820. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3821. +*/
  3822. +
  3823. +#include <map>
  3824. +
  3825. +#include "base/values.h"
  3826. +#include "base/strings/string_number_conversions.h"
  3827. +#include "base/json/json_writer.h"
  3828. +
  3829. +#include "chrome/browser/browser_process.h"
  3830. +#include "chrome/browser/profiles/profile.h"
  3831. +#include "chrome/browser/profiles/profile_manager.h"
  3832. +
  3833. +#include "components/prefs/pref_service.h"
  3834. +#include "components/prefs/scoped_user_pref_update.h"
  3835. +#include "components/pref_registry/pref_registry_syncable.h"
  3836. +#include "user_script_prefs.h"
  3837. +#include "user_script_pref_info.h"
  3838. +#include "../common/user_script.h"
  3839. +#include "../common/user_scripts_features.h"
  3840. +
  3841. +namespace user_scripts {
  3842. +
  3843. +namespace prefs {
  3844. + const char kUserScriptsEnabled[] = "userscripts.enabled";
  3845. +}
  3846. +
  3847. +namespace {
  3848. +
  3849. +const char kUserScriptsStartup[] = "userscripts.startup";
  3850. +
  3851. +const char kUserScriptsList[] = "userscripts.scripts";
  3852. +const char kScriptIsEnabled[] = "enabled";
  3853. +const char kScriptName[] = "name";
  3854. +const char kScriptDescription[] = "description";
  3855. +const char kScriptVersion[] = "version";
  3856. +const char kScriptInstallTime[] = "install_time";
  3857. +const char kScriptFilePath[] = "file_path";
  3858. +const char kScriptUrlSource[] = "url_source";
  3859. +const char kScriptParserError[] = "parser_error";
  3860. +const char kScriptForceDisabled[] = "force_disabled";
  3861. +
  3862. +class PrefUpdate : public DictionaryPrefUpdate {
  3863. + public:
  3864. + PrefUpdate(PrefService* service,
  3865. + const std::string& id,
  3866. + const std::string& path)
  3867. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3868. +
  3869. + ~PrefUpdate() override = default;
  3870. +
  3871. + base::DictionaryValue* Get() override {
  3872. + base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
  3873. + base::Value* dict_item =
  3874. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3875. + if (!dict_item)
  3876. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3877. + return static_cast<base::DictionaryValue*>(dict_item);
  3878. + }
  3879. +
  3880. + private:
  3881. + const std::string id_;
  3882. +
  3883. + DISALLOW_COPY_AND_ASSIGN(PrefUpdate);
  3884. +};
  3885. +
  3886. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3887. + const std::string& key,
  3888. + int64_t* value) {
  3889. + DCHECK(dict);
  3890. + const std::string* value_str = dict->FindStringKey(key);
  3891. + if (!value_str) {
  3892. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3893. + << ".";
  3894. + return false;
  3895. + }
  3896. +
  3897. + if (!base::StringToInt64(*value_str, value)) {
  3898. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3899. + << *value_str << ".";
  3900. + return false;
  3901. + }
  3902. +
  3903. + return true;
  3904. +}
  3905. +
  3906. +}
  3907. +
  3908. +UserScriptsPrefs::UserScriptsPrefs(
  3909. + PrefService* prefs)
  3910. + : prefs_(prefs) {
  3911. +}
  3912. +
  3913. +// static
  3914. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3915. + registry->RegisterBooleanPref(prefs::kUserScriptsEnabled, false);
  3916. + registry->RegisterIntegerPref(kUserScriptsStartup, 0);
  3917. + registry->RegisterDictionaryPref(kUserScriptsList);
  3918. +}
  3919. +
  3920. +bool UserScriptsPrefs::IsEnabled() {
  3921. + return prefs_->GetBoolean(prefs::kUserScriptsEnabled);
  3922. +}
  3923. +
  3924. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3925. + prefs_->SetBoolean(prefs::kUserScriptsEnabled, enabled);
  3926. + prefs_->CommitPendingWrite();
  3927. +}
  3928. +
  3929. +void UserScriptsPrefs::StartupTryout(int number) {
  3930. + prefs_->SetInteger(kUserScriptsStartup, number);
  3931. + prefs_->CommitPendingWrite();
  3932. +}
  3933. +
  3934. +int UserScriptsPrefs::GetCurrentStartupTryout() {
  3935. + return prefs_->GetInteger(kUserScriptsStartup);
  3936. +}
  3937. +
  3938. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3939. + if (IsEnabled() == false) {
  3940. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3941. + LOG(INFO) << "UserScriptsPrefs: disabled by user";
  3942. +
  3943. + user_scripts.clear();
  3944. + return;
  3945. + }
  3946. +
  3947. + std::vector<std::string> all_scripts;
  3948. +
  3949. + auto it = user_scripts.begin();
  3950. + while (it != user_scripts.end())
  3951. + {
  3952. + std::string key = it->get()->key();
  3953. + all_scripts.push_back(key);
  3954. +
  3955. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  3956. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  3957. +
  3958. + // add or update prefs
  3959. + scriptInfo->set_name(it->get()->name());
  3960. + scriptInfo->set_description(it->get()->description());
  3961. + scriptInfo->set_version(it->get()->version());
  3962. + scriptInfo->set_file_path(it->get()->file_path());
  3963. + scriptInfo->set_url_source(it->get()->url_source());
  3964. + scriptInfo->set_parser_error(it->get()->parser_error());
  3965. + scriptInfo->force_disabled = (it->get()->force_disabled());
  3966. +
  3967. + PrefUpdate update(prefs_, key, kUserScriptsList);
  3968. + base::DictionaryValue* script_dict = update.Get();
  3969. +
  3970. + script_dict->SetString(kScriptName, scriptInfo->name());
  3971. + script_dict->SetString(kScriptDescription, scriptInfo->description());
  3972. + script_dict->SetBoolean(kScriptIsEnabled, scriptInfo->enabled);
  3973. + script_dict->SetString(kScriptVersion, scriptInfo->version());
  3974. + script_dict->SetString(kScriptFilePath, scriptInfo->file_path());
  3975. + script_dict->SetString(kScriptUrlSource, scriptInfo->url_source());
  3976. + script_dict->SetString(kScriptParserError, scriptInfo->parser_error());
  3977. + script_dict->SetBoolean(kScriptForceDisabled, scriptInfo->force_disabled);
  3978. +
  3979. + std::string install_time_str =
  3980. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  3981. + script_dict->SetString(kScriptInstallTime, install_time_str);
  3982. +
  3983. + if (!scriptInfo->enabled) {
  3984. + it = user_scripts.erase(it);
  3985. + } else {
  3986. + ++it;
  3987. + }
  3988. + }
  3989. +
  3990. + // remove script from prefs if no more present
  3991. + std::vector<std::string> all_scripts_to_remove;
  3992. + const base::DictionaryValue* dict =
  3993. + prefs_->GetDictionary(kUserScriptsList);
  3994. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  3995. + script_it.Advance()) {
  3996. + const std::string& key = script_it.key();
  3997. +
  3998. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  3999. + all_scripts_to_remove.push_back(key);
  4000. + }
  4001. + }
  4002. +
  4003. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4004. + base::DictionaryValue* const update_dict = update.Get();
  4005. + for (auto key : all_scripts_to_remove) {
  4006. + update_dict->RemoveKey(key);
  4007. + }
  4008. +
  4009. + return;
  4010. +}
  4011. +
  4012. +std::string UserScriptsPrefs::GetScriptsInfo() {
  4013. + std::string json_string;
  4014. +
  4015. + const base::DictionaryValue* dict =
  4016. + prefs_->GetDictionary(kUserScriptsList);
  4017. +
  4018. + if (dict) {
  4019. + base::JSONWriter::WriteWithOptions(
  4020. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  4021. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  4022. + }
  4023. +
  4024. + return json_string;
  4025. +}
  4026. +
  4027. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  4028. + const std::string& script_id) const {
  4029. +
  4030. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  4031. + script_id, "", base::Time::Now(), false);
  4032. +
  4033. + const base::DictionaryValue* scripts =
  4034. + prefs_->GetDictionary(kUserScriptsList);
  4035. + if (!scripts)
  4036. + return scriptInfo;
  4037. +
  4038. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  4039. + scripts->FindDictKey(script_id));
  4040. + if (!script)
  4041. + return scriptInfo;
  4042. +
  4043. + const std::string* name = script->FindStringKey(kScriptName);
  4044. + const std::string* description = script->FindStringKey(kScriptDescription);
  4045. + const std::string* version = script->FindStringKey(kScriptVersion);
  4046. + const std::string* file_path = script->FindStringKey(kScriptFilePath);
  4047. + const std::string* url_source = script->FindStringKey(kScriptUrlSource);
  4048. + const std::string* parser_error = script->FindStringKey(kScriptParserError);
  4049. +
  4050. + scriptInfo->set_name( name ? *name : "no name" );
  4051. + scriptInfo->set_description( description ? *description : "no description" );
  4052. + scriptInfo->set_version( version ? *version : "no version" );
  4053. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  4054. + scriptInfo->set_file_path( file_path ? *file_path : "no file path" );
  4055. + scriptInfo->set_url_source( url_source ? *url_source : "" );
  4056. + scriptInfo->set_parser_error( parser_error ? *parser_error : "" );
  4057. + scriptInfo->force_disabled = script->FindBoolKey(kScriptForceDisabled).value_or(false);
  4058. +
  4059. + int64_t time_interval = 0;
  4060. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  4061. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  4062. + }
  4063. +
  4064. + return scriptInfo;
  4065. +}
  4066. +
  4067. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  4068. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4069. + base::DictionaryValue* const update_dict = update.Get();
  4070. + update_dict->RemoveKey(script_id);
  4071. +}
  4072. +
  4073. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  4074. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  4075. + base::DictionaryValue* script_dict = update.Get();
  4076. + if (script_dict->FindBoolKey(kScriptForceDisabled).value_or(false))
  4077. + is_enabled = true;
  4078. + script_dict->SetBoolean(kScriptIsEnabled, is_enabled);
  4079. +}
  4080. +
  4081. +}
  4082. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  4083. new file mode 100644
  4084. --- /dev/null
  4085. +++ b/components/user_scripts/browser/user_script_prefs.h
  4086. @@ -0,0 +1,62 @@
  4087. +/*
  4088. + This file is part of Bromite.
  4089. +
  4090. + Bromite is free software: you can redistribute it and/or modify
  4091. + it under the terms of the GNU General Public License as published by
  4092. + the Free Software Foundation, either version 3 of the License, or
  4093. + (at your option) any later version.
  4094. +
  4095. + Bromite is distributed in the hope that it will be useful,
  4096. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4097. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4098. + GNU General Public License for more details.
  4099. +
  4100. + You should have received a copy of the GNU General Public License
  4101. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4102. +*/
  4103. +
  4104. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4105. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4106. +
  4107. +#include "content/public/browser/browser_context.h"
  4108. +#include "components/prefs/pref_service.h"
  4109. +#include "components/pref_registry/pref_registry_syncable.h"
  4110. +
  4111. +#include "user_script_pref_info.h"
  4112. +#include "../common/user_script.h"
  4113. +
  4114. +namespace user_scripts {
  4115. +
  4116. +namespace prefs {
  4117. + extern const char kUserScriptsEnabled[];
  4118. +}
  4119. +
  4120. +class UserScriptsPrefs {
  4121. + public:
  4122. + UserScriptsPrefs(
  4123. + PrefService* prefs);
  4124. +
  4125. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  4126. +
  4127. + bool IsEnabled();
  4128. + void SetEnabled(bool enabled);
  4129. +
  4130. + void StartupTryout(int number);
  4131. + int GetCurrentStartupTryout();
  4132. +
  4133. + void CompareWithPrefs(UserScriptList& user_scripts);
  4134. +
  4135. + std::string GetScriptsInfo();
  4136. + void RemoveScriptFromPrefs(const std::string& script_id);
  4137. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  4138. +
  4139. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  4140. + const std::string& script_id) const;
  4141. +
  4142. + private:
  4143. + PrefService* prefs_;
  4144. +};
  4145. +
  4146. +}
  4147. +
  4148. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4149. \ No newline at end of file
  4150. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  4151. new file mode 100755
  4152. --- /dev/null
  4153. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  4154. @@ -0,0 +1,78 @@
  4155. +/*
  4156. + This file is part of Bromite.
  4157. +
  4158. + Bromite is free software: you can redistribute it and/or modify
  4159. + it under the terms of the GNU General Public License as published by
  4160. + the Free Software Foundation, either version 3 of the License, or
  4161. + (at your option) any later version.
  4162. +
  4163. + Bromite is distributed in the hope that it will be useful,
  4164. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4165. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4166. + GNU General Public License for more details.
  4167. +
  4168. + You should have received a copy of the GNU General Public License
  4169. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4170. +*/
  4171. +
  4172. +#include "userscripts_browser_client.h"
  4173. +
  4174. +#include "base/logging.h"
  4175. +
  4176. +#include "chrome/browser/browser_process.h"
  4177. +
  4178. +#include "chrome/browser/profiles/profile.h"
  4179. +#include "chrome/browser/profiles/profile_manager.h"
  4180. +
  4181. +#include "../common/user_scripts_features.h"
  4182. +#include "user_script_loader.h"
  4183. +#include "file_task_runner.h"
  4184. +#include "user_script_prefs.h"
  4185. +
  4186. +namespace user_scripts {
  4187. +
  4188. +namespace {
  4189. +
  4190. +// remember: was ExtensionsBrowserClient
  4191. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  4192. +
  4193. +} // namespace
  4194. +
  4195. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  4196. +
  4197. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  4198. +
  4199. +// static
  4200. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  4201. + // only for browser process
  4202. + if (!g_browser_process)
  4203. + return NULL;
  4204. +
  4205. + // singleton
  4206. + if (g_userscripts_browser_client)
  4207. + return g_userscripts_browser_client;
  4208. +
  4209. + // make file task runner
  4210. + GetUserScriptsFileTaskRunner().get();
  4211. +
  4212. + // new instance singleton
  4213. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  4214. +
  4215. + return g_userscripts_browser_client;
  4216. +}
  4217. +
  4218. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  4219. + browser_context_ = context;
  4220. +
  4221. + prefs_ =
  4222. + std::make_unique<user_scripts::UserScriptsPrefs>(
  4223. + static_cast<Profile*>(context)->GetPrefs());
  4224. +
  4225. + userscript_loader_ =
  4226. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  4227. + if (prefs_->IsEnabled()) {
  4228. + userscript_loader_->SetReady(true);
  4229. + }
  4230. +}
  4231. +
  4232. +} // namespace user_scripts
  4233. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  4234. new file mode 100755
  4235. --- /dev/null
  4236. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  4237. @@ -0,0 +1,62 @@
  4238. +/*
  4239. + This file is part of Bromite.
  4240. +
  4241. + Bromite is free software: you can redistribute it and/or modify
  4242. + it under the terms of the GNU General Public License as published by
  4243. + the Free Software Foundation, either version 3 of the License, or
  4244. + (at your option) any later version.
  4245. +
  4246. + Bromite is distributed in the hope that it will be useful,
  4247. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4248. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4249. + GNU General Public License for more details.
  4250. +
  4251. + You should have received a copy of the GNU General Public License
  4252. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4253. +*/
  4254. +
  4255. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4256. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4257. +
  4258. +#include <memory>
  4259. +#include <string>
  4260. +#include <vector>
  4261. +
  4262. +#include "content/public/browser/browser_context.h"
  4263. +
  4264. +#include "../common/user_script.h"
  4265. +#include "user_script_loader.h"
  4266. +#include "user_script_prefs.h"
  4267. +
  4268. +namespace user_scripts {
  4269. +
  4270. +class UserScriptsBrowserClient {
  4271. + public:
  4272. + UserScriptsBrowserClient();
  4273. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  4274. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  4275. + virtual ~UserScriptsBrowserClient();
  4276. +
  4277. + // Returns the single instance of |this|.
  4278. + static UserScriptsBrowserClient* GetInstance();
  4279. +
  4280. + void SetProfile(content::BrowserContext* context);
  4281. +
  4282. + user_scripts::UserScriptsPrefs* GetPrefs() {
  4283. + return prefs_.get();
  4284. + }
  4285. +
  4286. + user_scripts::UserScriptLoader* GetLoader() {
  4287. + return userscript_loader_.get();
  4288. + }
  4289. +
  4290. + private:
  4291. + std::unique_ptr<UserScriptList> scripts_;
  4292. + content::BrowserContext* browser_context_;
  4293. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  4294. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  4295. +};
  4296. +
  4297. +} // namespace extensions
  4298. +
  4299. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4300. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  4301. new file mode 100755
  4302. --- /dev/null
  4303. +++ b/components/user_scripts/common/BUILD.gn
  4304. @@ -0,0 +1,49 @@
  4305. +# Copyright 2014 The Chromium Authors. All rights reserved.
  4306. +# Use of this source code is governed by a BSD-style license that can be
  4307. +# found in the LICENSE file.
  4308. +
  4309. +import("//build/config/features.gni")
  4310. +import("//mojo/public/tools/bindings/mojom.gni")
  4311. +
  4312. +static_library("common") {
  4313. + sources = [
  4314. + "user_scripts_features.cc",
  4315. + "user_scripts_features.h",
  4316. + "constants.h",
  4317. + "host_id.cc",
  4318. + "host_id.h",
  4319. + "script_constants.h",
  4320. + "url_pattern_set.cc",
  4321. + "url_pattern_set.h",
  4322. + "url_pattern.cc",
  4323. + "url_pattern.h",
  4324. + "user_script.cc",
  4325. + "user_script.h",
  4326. + "view_type.cc",
  4327. + "view_type.h",
  4328. + "extension_messages.cc",
  4329. + "extension_messages.h",
  4330. + "extension_message_generator.cc",
  4331. + "extension_message_generator.h",
  4332. + ]
  4333. +
  4334. + configs += [
  4335. + "//build/config:precompiled_headers",
  4336. + "//build/config/compiler:wexit_time_destructors",
  4337. + ]
  4338. +
  4339. + public_deps = [
  4340. + "//components/services/app_service/public/cpp:app_file_handling",
  4341. + "//content/public/common",
  4342. + "//ipc",
  4343. + "//skia",
  4344. + ]
  4345. +
  4346. + deps = [
  4347. + "//base",
  4348. + "//components/url_formatter",
  4349. + "//components/url_matcher",
  4350. + "//components/version_info",
  4351. + "//crypto",
  4352. + ]
  4353. +}
  4354. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  4355. new file mode 100755
  4356. --- /dev/null
  4357. +++ b/components/user_scripts/common/constants.h
  4358. @@ -0,0 +1,21 @@
  4359. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4360. +// Use of this source code is governed by a BSD-style license that can be
  4361. +// found in the LICENSE file.
  4362. +
  4363. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  4364. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  4365. +
  4366. +#include "base/files/file_path.h"
  4367. +#include "base/strings/string_piece_forward.h"
  4368. +#include "components/services/app_service/public/mojom/types.mojom.h"
  4369. +#include "components/version_info/channel.h"
  4370. +#include "ui/base/layout.h"
  4371. +
  4372. +namespace user_scripts {
  4373. +
  4374. +// The origin of injected CSS.
  4375. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  4376. +
  4377. +} // namespace user_scripts
  4378. +
  4379. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  4380. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  4381. new file mode 100755
  4382. --- /dev/null
  4383. +++ b/components/user_scripts/common/error_utils.cc
  4384. @@ -0,0 +1,54 @@
  4385. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4386. +// Use of this source code is governed by a BSD-style license that can be
  4387. +// found in the LICENSE file.
  4388. +
  4389. +#include "error_utils.h"
  4390. +
  4391. +#include <initializer_list>
  4392. +
  4393. +#include "base/check_op.h"
  4394. +#include "base/strings/string_tokenizer.h"
  4395. +#include "base/strings/string_util.h"
  4396. +#include "base/strings/utf_string_conversions.h"
  4397. +
  4398. +namespace user_scripts {
  4399. +
  4400. +namespace {
  4401. +
  4402. +std::string FormatErrorMessageInternal(
  4403. + base::StringPiece format,
  4404. + std::initializer_list<base::StringPiece> args) {
  4405. + std::string format_str = format.as_string();
  4406. + base::StringTokenizer tokenizer(format_str, "*");
  4407. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  4408. +
  4409. + std::vector<base::StringPiece> result_pieces;
  4410. + auto* args_it = args.begin();
  4411. + while (tokenizer.GetNext()) {
  4412. + if (!tokenizer.token_is_delim()) {
  4413. + result_pieces.push_back(tokenizer.token_piece());
  4414. + continue;
  4415. + }
  4416. +
  4417. + CHECK_NE(args_it, args.end())
  4418. + << "More placeholders (*) than substitutions.";
  4419. +
  4420. + // Substitute the argument.
  4421. + result_pieces.push_back(*args_it);
  4422. + args_it++;
  4423. + }
  4424. +
  4425. + // Not all substitutions were consumed.
  4426. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  4427. +
  4428. + return base::JoinString(result_pieces, "" /* separator */);
  4429. +}
  4430. +
  4431. +} // namespace
  4432. +
  4433. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  4434. + base::StringPiece s1) {
  4435. + return FormatErrorMessageInternal(format, {s1});
  4436. +}
  4437. +
  4438. +} // namespace user_scripts
  4439. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  4440. new file mode 100755
  4441. --- /dev/null
  4442. +++ b/components/user_scripts/common/error_utils.h
  4443. @@ -0,0 +1,24 @@
  4444. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4445. +// Use of this source code is governed by a BSD-style license that can be
  4446. +// found in the LICENSE file.
  4447. +
  4448. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4449. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4450. +
  4451. +#include <string>
  4452. +
  4453. +#include "base/strings/string_piece.h"
  4454. +
  4455. +namespace user_scripts {
  4456. +
  4457. +class ErrorUtils {
  4458. + public:
  4459. + // Creates an error messages from a pattern.
  4460. + static std::string FormatErrorMessage(base::StringPiece format,
  4461. + base::StringPiece s1);
  4462. +
  4463. +};
  4464. +
  4465. +} // namespace extensions
  4466. +
  4467. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4468. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  4469. new file mode 100755
  4470. --- /dev/null
  4471. +++ b/components/user_scripts/common/extension_message_generator.cc
  4472. @@ -0,0 +1,29 @@
  4473. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4474. +// Use of this source code is governed by a BSD-style license that can be
  4475. +// found in the LICENSE file.
  4476. +
  4477. +// Get basic type definitions.
  4478. +#define IPC_MESSAGE_IMPL
  4479. +#include "components/user_scripts/common/extension_message_generator.h"
  4480. +
  4481. +// Generate constructors.
  4482. +#include "ipc/struct_constructor_macros.h"
  4483. +#include "components/user_scripts/common/extension_message_generator.h"
  4484. +
  4485. +// Generate param traits write methods.
  4486. +#include "ipc/param_traits_write_macros.h"
  4487. +namespace IPC {
  4488. +#include "components/user_scripts/common/extension_message_generator.h"
  4489. +} // namespace IPC
  4490. +
  4491. +// Generate param traits read methods.
  4492. +#include "ipc/param_traits_read_macros.h"
  4493. +namespace IPC {
  4494. +#include "components/user_scripts/common/extension_message_generator.h"
  4495. +} // namespace IPC
  4496. +
  4497. +// Generate param traits log methods.
  4498. +#include "ipc/param_traits_log_macros.h"
  4499. +namespace IPC {
  4500. +#include "components/user_scripts/common/extension_message_generator.h"
  4501. +} // namespace IPC
  4502. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  4503. new file mode 100755
  4504. --- /dev/null
  4505. +++ b/components/user_scripts/common/extension_message_generator.h
  4506. @@ -0,0 +1,11 @@
  4507. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4508. +// Use of this source code is governed by a BSD-style license that can be
  4509. +// found in the LICENSE file.
  4510. +
  4511. +// Multiply-included file, hence no include guard.
  4512. +
  4513. +#undef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4514. +#include "extension_messages.h"
  4515. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4516. +#error "Failed to include header extension_messages.h"
  4517. +#endif
  4518. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  4519. new file mode 100755
  4520. --- /dev/null
  4521. +++ b/components/user_scripts/common/extension_messages.cc
  4522. @@ -0,0 +1,40 @@
  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. +#include "extension_messages.h"
  4528. +
  4529. +#include <stddef.h>
  4530. +
  4531. +#include <memory>
  4532. +#include <utility>
  4533. +
  4534. +#include "content/public/common/common_param_traits.h"
  4535. +
  4536. +namespace IPC {
  4537. +
  4538. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  4539. + WriteParam(m, p.type());
  4540. + WriteParam(m, p.id());
  4541. +}
  4542. +
  4543. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  4544. + base::PickleIterator* iter,
  4545. + param_type* r) {
  4546. + HostID::HostType type;
  4547. + std::string id;
  4548. + if (!ReadParam(m, iter, &type))
  4549. + return false;
  4550. + if (!ReadParam(m, iter, &id))
  4551. + return false;
  4552. + *r = HostID(type, id);
  4553. + return true;
  4554. +}
  4555. +
  4556. +void ParamTraits<HostID>::Log(
  4557. + const param_type& p, std::string* l) {
  4558. + LogParam(p.type(), l);
  4559. + LogParam(p.id(), l);
  4560. +}
  4561. +
  4562. +} // namespace IPC
  4563. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  4564. new file mode 100755
  4565. --- /dev/null
  4566. +++ b/components/user_scripts/common/extension_messages.h
  4567. @@ -0,0 +1,71 @@
  4568. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4569. +// Use of this source code is governed by a BSD-style license that can be
  4570. +// found in the LICENSE file.
  4571. +
  4572. +// IPC messages for extensions.
  4573. +
  4574. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4575. +#define USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4576. +
  4577. +#include <stdint.h>
  4578. +
  4579. +#include <map>
  4580. +#include <memory>
  4581. +#include <set>
  4582. +#include <string>
  4583. +#include <vector>
  4584. +
  4585. +#include "base/macros.h"
  4586. +#include "base/memory/read_only_shared_memory_region.h"
  4587. +#include "base/values.h"
  4588. +#include "content/public/common/common_param_traits.h"
  4589. +#include "constants.h"
  4590. +#include "host_id.h"
  4591. +#include "ipc/ipc_message_start.h"
  4592. +#include "ipc/ipc_message_macros.h"
  4593. +#include "url/gurl.h"
  4594. +#include "url/origin.h"
  4595. +
  4596. +#define IPC_MESSAGE_START ExtensionMsgStart
  4597. +
  4598. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  4599. +
  4600. +// Singly-included section for custom IPC traits.
  4601. +#ifndef INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4602. +#define INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4603. +
  4604. +namespace IPC {
  4605. +
  4606. +template <>
  4607. +struct ParamTraits<HostID> {
  4608. + typedef HostID param_type;
  4609. + static void Write(base::Pickle* m, const param_type& p);
  4610. + static bool Read(const base::Pickle* m,
  4611. + base::PickleIterator* iter,
  4612. + param_type* r);
  4613. + static void Log(const param_type& p, std::string* l);
  4614. +};
  4615. +
  4616. +
  4617. +} // namespace IPC
  4618. +
  4619. +#endif // INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4620. +
  4621. +// Notification that the user scripts have been updated. It has one
  4622. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  4623. +// This memory region is valid in the context of the renderer.
  4624. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  4625. +// programmatically-defined scripts. Otherwise, the handle refers to all
  4626. +// hosts' statically defined scripts. So far, only extension-hosts support
  4627. +// statically defined scripts; WebUI-hosts don't.
  4628. +// If |changed_hosts| is not empty, only the host in that set will
  4629. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  4630. +// region will be updated. Note that the empty set => all hosts case is not
  4631. +// supported for per-extension programmatically-defined script regions; in such
  4632. +// regions, the owner is expected to list itself as the only changed host.
  4633. +// If |whitelisted_only| is true, this process should only run whitelisted
  4634. +// scripts and not all user scripts.
  4635. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  4636. + base::ReadOnlySharedMemoryRegion)
  4637. +
  4638. +#endif // USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4639. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  4640. new file mode 100755
  4641. --- /dev/null
  4642. +++ b/components/user_scripts/common/host_id.cc
  4643. @@ -0,0 +1,31 @@
  4644. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4645. +// Use of this source code is governed by a BSD-style license that can be
  4646. +// found in the LICENSE file.
  4647. +
  4648. +#include "host_id.h"
  4649. +
  4650. +#include <tuple>
  4651. +
  4652. +HostID::HostID()
  4653. + : type_(HostType::EXTENSIONS) {
  4654. +}
  4655. +
  4656. +HostID::HostID(HostType type, const std::string& id)
  4657. + : type_(type), id_(id) {
  4658. +}
  4659. +
  4660. +HostID::HostID(const HostID& host_id)
  4661. + : type_(host_id.type()),
  4662. + id_(host_id.id()) {
  4663. +}
  4664. +
  4665. +HostID::~HostID() {
  4666. +}
  4667. +
  4668. +bool HostID::operator<(const HostID& host_id) const {
  4669. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  4670. +}
  4671. +
  4672. +bool HostID::operator==(const HostID& host_id) const {
  4673. + return type_ == host_id.type_ && id_ == host_id.id_;
  4674. +}
  4675. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  4676. new file mode 100755
  4677. --- /dev/null
  4678. +++ b/components/user_scripts/common/host_id.h
  4679. @@ -0,0 +1,35 @@
  4680. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4681. +// Use of this source code is governed by a BSD-style license that can be
  4682. +// found in the LICENSE file.
  4683. +
  4684. +#ifndef USERSCRIPTS_COMMON_HOST_ID_H_
  4685. +#define USERSCRIPTS_COMMON_HOST_ID_H_
  4686. +
  4687. +#include <string>
  4688. +
  4689. +// IDs of hosts who own user scripts.
  4690. +// A HostID is immutable after creation.
  4691. +struct HostID {
  4692. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  4693. +
  4694. + HostID();
  4695. + HostID(HostType type, const std::string& id);
  4696. + HostID(const HostID& host_id);
  4697. + ~HostID();
  4698. +
  4699. + bool operator<(const HostID& host_id) const;
  4700. + bool operator==(const HostID& host_id) const;
  4701. +
  4702. + HostType type() const { return type_; }
  4703. + const std::string& id() const { return id_; }
  4704. +
  4705. + private:
  4706. + // The type of the host.
  4707. + HostType type_;
  4708. +
  4709. + // Similar to extension_id, host_id is a unique indentifier for a host,
  4710. + // e.g., an Extension or WebUI.
  4711. + std::string id_;
  4712. +};
  4713. +
  4714. +#endif // USERSCRIPTS_COMMON_HOST_ID_H_
  4715. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  4716. new file mode 100755
  4717. --- /dev/null
  4718. +++ b/components/user_scripts/common/script_constants.h
  4719. @@ -0,0 +1,33 @@
  4720. +// Copyright 2020 The Chromium Authors. All rights reserved.
  4721. +// Use of this source code is governed by a BSD-style license that can be
  4722. +// found in the LICENSE file.
  4723. +
  4724. +#ifndef USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4725. +#define USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4726. +
  4727. +namespace user_scripts {
  4728. +
  4729. +// Whether to fall back to matching the origin for frames where the URL
  4730. +// cannot be matched directly, such as those with about: or data: schemes.
  4731. +enum class MatchOriginAsFallbackBehavior {
  4732. + // Never fall back on the origin; this means scripts will never match on
  4733. + // these frames.
  4734. + kNever,
  4735. + // Match the origin only for about:-scheme frames, and then climb the frame
  4736. + // tree to find an appropriate ancestor to get a full URL (including path).
  4737. + // This is for supporting the "match_about_blank" key.
  4738. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  4739. + // and not worry about climbing the frame tree. It would be a behavior
  4740. + // change, but I wonder how many extensions it would impact in practice.
  4741. + kMatchForAboutSchemeAndClimbTree,
  4742. + // Match the origin as a fallback whenever applicable. This won't have a
  4743. + // corresponding path.
  4744. + kAlways,
  4745. +};
  4746. +
  4747. +// TODO(devlin): Move the other non-UserScript-specific constants like
  4748. +// RunLocation and InjectionType from UserScript into here.
  4749. +
  4750. +}
  4751. +
  4752. +#endif // USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4753. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  4754. new file mode 100755
  4755. --- /dev/null
  4756. +++ b/components/user_scripts/common/url_pattern.cc
  4757. @@ -0,0 +1,803 @@
  4758. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4759. +// Use of this source code is governed by a BSD-style license that can be
  4760. +// found in the LICENSE file.
  4761. +
  4762. +#include "url_pattern.h"
  4763. +
  4764. +#include <stddef.h>
  4765. +
  4766. +#include <ostream>
  4767. +
  4768. +#include "base/logging.h"
  4769. +#include "base/strings/pattern.h"
  4770. +#include "base/strings/strcat.h"
  4771. +#include "base/strings/string_number_conversions.h"
  4772. +#include "base/strings/string_piece.h"
  4773. +#include "base/strings/string_split.h"
  4774. +#include "base/strings/string_util.h"
  4775. +#include "base/strings/stringprintf.h"
  4776. +#include "content/public/common/url_constants.h"
  4777. +#include "constants.h"
  4778. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4779. +#include "net/base/url_util.h"
  4780. +#include "url/gurl.h"
  4781. +#include "url/url_util.h"
  4782. +
  4783. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4784. +
  4785. +namespace {
  4786. +
  4787. +// TODO(aa): What about more obscure schemes like javascript: ?
  4788. +// Note: keep this array in sync with kValidSchemeMasks.
  4789. +const char* const kValidSchemes[] = {
  4790. + url::kHttpScheme, url::kHttpsScheme,
  4791. + url::kFileScheme, url::kFtpScheme,
  4792. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4793. + url::kFileSystemScheme, url::kWsScheme,
  4794. + url::kWssScheme, url::kDataScheme,
  4795. + url::kUrnScheme,
  4796. +};
  4797. +
  4798. +const int kValidSchemeMasks[] = {
  4799. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4800. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4801. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4802. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4803. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4804. + URLPattern::SCHEME_URN,
  4805. +};
  4806. +
  4807. +static_assert(base::size(kValidSchemes) == base::size(kValidSchemeMasks),
  4808. + "must keep these arrays in sync");
  4809. +
  4810. +const char kParseSuccess[] = "Success.";
  4811. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4812. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4813. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4814. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4815. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4816. +const char kParseErrorEmptyPath[] = "Empty path.";
  4817. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4818. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4819. +
  4820. +// Message explaining each URLPattern::ParseResult.
  4821. +const char* const kParseResultMessages[] = {
  4822. + kParseSuccess,
  4823. + kParseErrorMissingSchemeSeparator,
  4824. + kParseErrorInvalidScheme,
  4825. + kParseErrorWrongSchemeType,
  4826. + kParseErrorEmptyHost,
  4827. + kParseErrorInvalidHostWildcard,
  4828. + kParseErrorEmptyPath,
  4829. + kParseErrorInvalidPort,
  4830. + kParseErrorInvalidHost,
  4831. +};
  4832. +
  4833. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4834. + base::size(kParseResultMessages),
  4835. + "must add message for each parse result");
  4836. +
  4837. +const char kPathSeparator[] = "/";
  4838. +
  4839. +bool IsStandardScheme(base::StringPiece scheme) {
  4840. + // "*" gets the same treatment as a standard scheme.
  4841. + if (scheme == "*")
  4842. + return true;
  4843. +
  4844. + return url::IsStandard(scheme.data(),
  4845. + url::Component(0, static_cast<int>(scheme.length())));
  4846. +}
  4847. +
  4848. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4849. + if (port == "*")
  4850. + return true;
  4851. +
  4852. + // Only accept non-wildcard ports if the scheme uses ports.
  4853. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4854. + url::PORT_UNSPECIFIED) {
  4855. + return false;
  4856. + }
  4857. +
  4858. + int parsed_port = url::PORT_UNSPECIFIED;
  4859. + if (!base::StringToInt(port, &parsed_port))
  4860. + return false;
  4861. + return (parsed_port >= 0) && (parsed_port < 65536);
  4862. +}
  4863. +
  4864. +// Returns |path| with the trailing wildcard stripped if one existed.
  4865. +//
  4866. +// The functions that rely on this (OverlapsWith and Contains) are only
  4867. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4868. +// the path will have only a single wildcard at the end. This makes figuring
  4869. +// out overlap much easier. It seems like there is probably a computer-sciency
  4870. +// way to solve the general case, but we don't need that yet.
  4871. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4872. + if (base::EndsWith(path, "*"))
  4873. + path.remove_suffix(1);
  4874. + return path;
  4875. +}
  4876. +
  4877. +// Removes trailing dot from |host_piece| if any.
  4878. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4879. + if (base::EndsWith(host_piece, "."))
  4880. + host_piece.remove_suffix(1);
  4881. + return host_piece;
  4882. +}
  4883. +
  4884. +} // namespace
  4885. +
  4886. +// static
  4887. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4888. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4889. + if (scheme == kValidSchemes[i])
  4890. + return true;
  4891. + }
  4892. + return false;
  4893. +}
  4894. +
  4895. +// static
  4896. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4897. + int result = 0;
  4898. + for (size_t i = 0; i < base::size(kValidSchemeMasks); ++i)
  4899. + result |= kValidSchemeMasks[i];
  4900. + return result;
  4901. +}
  4902. +
  4903. +URLPattern::URLPattern()
  4904. + : valid_schemes_(SCHEME_NONE),
  4905. + match_all_urls_(false),
  4906. + match_subdomains_(false),
  4907. + port_("*") {}
  4908. +
  4909. +URLPattern::URLPattern(int valid_schemes)
  4910. + : valid_schemes_(valid_schemes),
  4911. + match_all_urls_(false),
  4912. + match_subdomains_(false),
  4913. + port_("*") {}
  4914. +
  4915. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4916. + // Strict error checking is used, because this constructor is only
  4917. + // appropriate when we know |pattern| is valid.
  4918. + : valid_schemes_(valid_schemes),
  4919. + match_all_urls_(false),
  4920. + match_subdomains_(false),
  4921. + port_("*") {
  4922. + ParseResult result = Parse(pattern);
  4923. + DCHECK_EQ(ParseResult::kSuccess, result)
  4924. + << "Parsing unexpectedly failed for pattern: " << pattern << ": "
  4925. + << GetParseResultString(result);
  4926. +}
  4927. +
  4928. +URLPattern::URLPattern(const URLPattern& other) = default;
  4929. +
  4930. +URLPattern::URLPattern(URLPattern&& other) = default;
  4931. +
  4932. +URLPattern::~URLPattern() {
  4933. +}
  4934. +
  4935. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4936. +
  4937. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4938. +
  4939. +bool URLPattern::operator<(const URLPattern& other) const {
  4940. + return GetAsString() < other.GetAsString();
  4941. +}
  4942. +
  4943. +bool URLPattern::operator>(const URLPattern& other) const {
  4944. + return GetAsString() > other.GetAsString();
  4945. +}
  4946. +
  4947. +bool URLPattern::operator==(const URLPattern& other) const {
  4948. + return GetAsString() == other.GetAsString();
  4949. +}
  4950. +
  4951. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4952. + return out << '"' << url_pattern.GetAsString() << '"';
  4953. +}
  4954. +
  4955. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  4956. + spec_.clear();
  4957. + SetMatchAllURLs(false);
  4958. + SetMatchSubdomains(false);
  4959. + SetPort("*");
  4960. +
  4961. + // Special case pattern to match every valid URL.
  4962. + if (pattern == kAllUrlsPattern) {
  4963. + SetMatchAllURLs(true);
  4964. + return ParseResult::kSuccess;
  4965. + }
  4966. +
  4967. + // Parse out the scheme.
  4968. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  4969. + bool has_standard_scheme_separator = true;
  4970. +
  4971. + // Some urls also use ':' alone as the scheme separator.
  4972. + if (scheme_end_pos == base::StringPiece::npos) {
  4973. + scheme_end_pos = pattern.find(':');
  4974. + has_standard_scheme_separator = false;
  4975. + }
  4976. +
  4977. + if (scheme_end_pos == base::StringPiece::npos)
  4978. + return ParseResult::kMissingSchemeSeparator;
  4979. +
  4980. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  4981. + return ParseResult::kInvalidScheme;
  4982. +
  4983. + bool standard_scheme = IsStandardScheme(scheme_);
  4984. + if (standard_scheme != has_standard_scheme_separator)
  4985. + return ParseResult::kWrongSchemeSeparator;
  4986. +
  4987. + // Advance past the scheme separator.
  4988. + scheme_end_pos +=
  4989. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  4990. + if (scheme_end_pos >= pattern.size())
  4991. + return ParseResult::kEmptyHost;
  4992. +
  4993. + // Parse out the host and path.
  4994. + size_t host_start_pos = scheme_end_pos;
  4995. + size_t path_start_pos = 0;
  4996. +
  4997. + if (!standard_scheme) {
  4998. + path_start_pos = host_start_pos;
  4999. + } else if (scheme_ == url::kFileScheme) {
  5000. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5001. + if (host_end_pos == base::StringPiece::npos) {
  5002. + // Allow hostname omission.
  5003. + // e.g. file://* is interpreted as file:///*,
  5004. + // file://foo* is interpreted as file:///foo*.
  5005. + path_start_pos = host_start_pos - 1;
  5006. + } else {
  5007. + // Ignore hostname if scheme is file://.
  5008. + // e.g. file://localhost/foo is equal to file:///foo.
  5009. + path_start_pos = host_end_pos;
  5010. + }
  5011. + } else {
  5012. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5013. +
  5014. + // Host is required.
  5015. + if (host_start_pos == host_end_pos)
  5016. + return ParseResult::kEmptyHost;
  5017. +
  5018. + if (host_end_pos == base::StringPiece::npos)
  5019. + return ParseResult::kEmptyPath;
  5020. +
  5021. + base::StringPiece host_and_port =
  5022. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  5023. +
  5024. + size_t port_separator_pos = base::StringPiece::npos;
  5025. + if (host_and_port[0] != '[') {
  5026. + // Not IPv6 (either IPv4 or just a normal address).
  5027. + port_separator_pos = host_and_port.find(':');
  5028. + } else { // IPv6.
  5029. + size_t host_end_pos = host_and_port.find(']');
  5030. + if (host_end_pos == base::StringPiece::npos)
  5031. + return ParseResult::kInvalidHost;
  5032. + if (host_end_pos == 1)
  5033. + return ParseResult::kEmptyHost;
  5034. +
  5035. + if (host_end_pos < host_and_port.length() - 1) {
  5036. + // The host isn't the only component. Check for a port. This would
  5037. + // require a ':' to follow the closing ']' from the host.
  5038. + if (host_and_port[host_end_pos + 1] != ':')
  5039. + return ParseResult::kInvalidHost;
  5040. +
  5041. + port_separator_pos = host_end_pos + 1;
  5042. + }
  5043. + }
  5044. +
  5045. + if (port_separator_pos != base::StringPiece::npos &&
  5046. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  5047. + return ParseResult::kInvalidPort;
  5048. + }
  5049. +
  5050. + // Note: this substr() will be the entire string if the port position
  5051. + // wasn't found.
  5052. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  5053. +
  5054. + if (host_piece.empty())
  5055. + return ParseResult::kEmptyHost;
  5056. +
  5057. + if (host_piece == "*") {
  5058. + match_subdomains_ = true;
  5059. + host_piece = base::StringPiece();
  5060. + } else if (base::StartsWith(host_piece, "*.")) {
  5061. + if (host_piece.length() == 2) {
  5062. + // We don't allow just '*.' as a host.
  5063. + return ParseResult::kEmptyHost;
  5064. + }
  5065. + match_subdomains_ = true;
  5066. + host_piece = host_piece.substr(2);
  5067. + }
  5068. +
  5069. + host_ = std::string(host_piece);
  5070. +
  5071. + path_start_pos = host_end_pos;
  5072. + }
  5073. +
  5074. + SetPath(pattern.substr(path_start_pos));
  5075. +
  5076. + // No other '*' can occur in the host, though. This isn't necessary, but is
  5077. + // done as a convenience to developers who might otherwise be confused and
  5078. + // think '*' works as a glob in the host.
  5079. + if (host_.find('*') != std::string::npos)
  5080. + return ParseResult::kInvalidHostWildcard;
  5081. +
  5082. + if (!host_.empty()) {
  5083. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  5084. + // it.
  5085. + url::CanonHostInfo host_info;
  5086. + host_ = net::CanonicalizeHost(host_, &host_info);
  5087. + // net::CanonicalizeHost() returns an empty string on failure.
  5088. + if (host_.empty())
  5089. + return ParseResult::kInvalidHost;
  5090. + }
  5091. +
  5092. + // Null characters are not allowed in hosts.
  5093. + if (host_.find('\0') != std::string::npos)
  5094. + return ParseResult::kInvalidHost;
  5095. +
  5096. + return ParseResult::kSuccess;
  5097. +}
  5098. +
  5099. +void URLPattern::SetValidSchemes(int valid_schemes) {
  5100. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  5101. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  5102. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  5103. + // http or https).
  5104. + spec_.clear();
  5105. + valid_schemes_ = valid_schemes;
  5106. +}
  5107. +
  5108. +void URLPattern::SetHost(base::StringPiece host) {
  5109. + spec_.clear();
  5110. + host_.assign(host.data(), host.size());
  5111. +}
  5112. +
  5113. +void URLPattern::SetMatchAllURLs(bool val) {
  5114. + spec_.clear();
  5115. + match_all_urls_ = val;
  5116. +
  5117. + if (val) {
  5118. + match_subdomains_ = true;
  5119. + scheme_ = "*";
  5120. + host_.clear();
  5121. + SetPath("/*");
  5122. + }
  5123. +}
  5124. +
  5125. +void URLPattern::SetMatchSubdomains(bool val) {
  5126. + spec_.clear();
  5127. + match_subdomains_ = val;
  5128. +}
  5129. +
  5130. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  5131. + spec_.clear();
  5132. + scheme_.assign(scheme.data(), scheme.size());
  5133. + if (scheme_ == "*") {
  5134. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  5135. + } else if (!IsValidScheme(scheme_)) {
  5136. + return false;
  5137. + }
  5138. + return true;
  5139. +}
  5140. +
  5141. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  5142. + if (valid_schemes_ == SCHEME_ALL)
  5143. + return true;
  5144. +
  5145. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5146. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  5147. + return true;
  5148. + }
  5149. +
  5150. + return false;
  5151. +}
  5152. +
  5153. +void URLPattern::SetPath(base::StringPiece path) {
  5154. + spec_.clear();
  5155. + path_.assign(path.data(), path.size());
  5156. + path_escaped_ = path_;
  5157. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  5158. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  5159. +}
  5160. +
  5161. +bool URLPattern::SetPort(base::StringPiece port) {
  5162. + spec_.clear();
  5163. + if (IsValidPortForScheme(scheme_, port)) {
  5164. + port_.assign(port.data(), port.size());
  5165. + return true;
  5166. + }
  5167. + return false;
  5168. +}
  5169. +
  5170. +bool URLPattern::MatchesURL(const GURL& test) const {
  5171. + // Invalid URLs can never match.
  5172. + if (!test.is_valid())
  5173. + return false;
  5174. +
  5175. + const GURL* test_url = &test;
  5176. + bool has_inner_url = test.inner_url() != nullptr;
  5177. +
  5178. + if (has_inner_url) {
  5179. + if (!test.SchemeIsFileSystem())
  5180. + return false; // The only nested URLs we handle are filesystem URLs.
  5181. + test_url = test.inner_url();
  5182. + }
  5183. +
  5184. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  5185. + // the scheme is excluded.
  5186. + if (!MatchesScheme(test_url->scheme_piece()))
  5187. + return false;
  5188. +
  5189. + if (match_all_urls_)
  5190. + return true;
  5191. +
  5192. + // Unless |match_all_urls_| is true, the grammar only permits matching
  5193. + // URLs with nonempty paths.
  5194. + if (!test.has_path())
  5195. + return false;
  5196. +
  5197. + std::string path_for_request = test.PathForRequest();
  5198. + if (has_inner_url) {
  5199. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  5200. + path_for_request.c_str());
  5201. + }
  5202. +
  5203. + return MatchesSecurityOriginHelper(*test_url) &&
  5204. + MatchesPath(path_for_request);
  5205. +}
  5206. +
  5207. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  5208. + const GURL* test_url = &test;
  5209. + bool has_inner_url = test.inner_url() != NULL;
  5210. +
  5211. + if (has_inner_url) {
  5212. + if (!test.SchemeIsFileSystem())
  5213. + return false; // The only nested URLs we handle are filesystem URLs.
  5214. + test_url = test.inner_url();
  5215. + }
  5216. +
  5217. + if (!MatchesScheme(test_url->scheme()))
  5218. + return false;
  5219. +
  5220. + if (match_all_urls_)
  5221. + return true;
  5222. +
  5223. + return MatchesSecurityOriginHelper(*test_url);
  5224. +}
  5225. +
  5226. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  5227. + if (!IsValidScheme(test))
  5228. + return false;
  5229. +
  5230. + return scheme_ == "*" || test == scheme_;
  5231. +}
  5232. +
  5233. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  5234. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  5235. + // important that we do this conversion to a GURL in order to canonicalize the
  5236. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  5237. + // just do string comparison.
  5238. + return MatchesHost(
  5239. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  5240. + url::kStandardSchemeSeparator, host.data())));
  5241. +}
  5242. +
  5243. +bool URLPattern::MatchesHost(const GURL& test) const {
  5244. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  5245. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  5246. +
  5247. + // If the hosts are exactly equal, we have a match.
  5248. + if (test_host == pattern_host)
  5249. + return true;
  5250. +
  5251. + // If we're matching subdomains, and we have no host in the match pattern,
  5252. + // that means that we're matching all hosts, which means we have a match no
  5253. + // matter what the test host is.
  5254. + if (match_subdomains_ && pattern_host.empty())
  5255. + return true;
  5256. +
  5257. + // Otherwise, we can only match if our match pattern matches subdomains.
  5258. + if (!match_subdomains_)
  5259. + return false;
  5260. +
  5261. + // We don't do subdomain matching against IP addresses, so we can give up now
  5262. + // if the test host is an IP address.
  5263. + if (test.HostIsIPAddress())
  5264. + return false;
  5265. +
  5266. + // Check if the test host is a subdomain of our host.
  5267. + if (test_host.length() <= (pattern_host.length() + 1))
  5268. + return false;
  5269. +
  5270. + if (!base::EndsWith(test_host, pattern_host))
  5271. + return false;
  5272. +
  5273. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  5274. +}
  5275. +
  5276. +bool URLPattern::MatchesEffectiveTld(
  5277. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  5278. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  5279. + const {
  5280. + // Check if it matches all urls or is a pattern like http://*/*.
  5281. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  5282. + return true;
  5283. +
  5284. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  5285. + if (!match_subdomains_)
  5286. + return false;
  5287. +
  5288. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  5289. + // doesn't match all hosts in an effective TLD.
  5290. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5291. + host_, unknown_filter, private_filter)) {
  5292. + return false;
  5293. + }
  5294. +
  5295. + // At this point the host could either be just a TLD ("com") or some unknown
  5296. + // TLD-like string ("notatld"). To disambiguate between them construct a
  5297. + // fake URL, and check the registry.
  5298. + //
  5299. + // If we recognized this TLD, then this is a pattern like *.com, and it
  5300. + // matches an effective TLD.
  5301. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5302. + "notatld." + host_, unknown_filter, private_filter);
  5303. +}
  5304. +
  5305. +bool URLPattern::MatchesSingleOrigin() const {
  5306. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  5307. + // defaults to *. It's not very interesting anyway, so leave it out.
  5308. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  5309. +}
  5310. +
  5311. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  5312. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  5313. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  5314. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  5315. + if (path_escaped_.length() == test.length() + 2 &&
  5316. + base::StartsWith(path_escaped_.c_str(), test) &&
  5317. + base::EndsWith(path_escaped_, "/*")) {
  5318. + return true;
  5319. + }
  5320. +
  5321. + return base::MatchPattern(test, path_escaped_);
  5322. +}
  5323. +
  5324. +const std::string& URLPattern::GetAsString() const {
  5325. + if (!spec_.empty())
  5326. + return spec_;
  5327. +
  5328. + if (match_all_urls_) {
  5329. + spec_ = kAllUrlsPattern;
  5330. + return spec_;
  5331. + }
  5332. +
  5333. + bool standard_scheme = IsStandardScheme(scheme_);
  5334. +
  5335. + std::string spec = scheme_ +
  5336. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  5337. +
  5338. + if (scheme_ != url::kFileScheme && standard_scheme) {
  5339. + if (match_subdomains_) {
  5340. + spec += "*";
  5341. + if (!host_.empty())
  5342. + spec += ".";
  5343. + }
  5344. +
  5345. + if (!host_.empty())
  5346. + spec += host_;
  5347. +
  5348. + if (port_ != "*") {
  5349. + spec += ":";
  5350. + spec += port_;
  5351. + }
  5352. + }
  5353. +
  5354. + if (!path_.empty())
  5355. + spec += path_;
  5356. +
  5357. + spec_ = std::move(spec);
  5358. + return spec_;
  5359. +}
  5360. +
  5361. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  5362. + if (match_all_urls() || other.match_all_urls())
  5363. + return true;
  5364. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  5365. + other.MatchesAnyScheme(GetExplicitSchemes()))
  5366. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  5367. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  5368. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  5369. + other.MatchesPath(StripTrailingWildcard(path())));
  5370. +}
  5371. +
  5372. +bool URLPattern::Contains(const URLPattern& other) const {
  5373. + // Important: it's not enough to just check match_all_urls(); we also need to
  5374. + // make sure that the schemes in this pattern are a superset of those in
  5375. + // |other|.
  5376. + if (match_all_urls() &&
  5377. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  5378. + return true;
  5379. + }
  5380. +
  5381. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  5382. + MatchesHost(other.host()) &&
  5383. + (!other.match_subdomains_ || match_subdomains_) &&
  5384. + MatchesPortPattern(other.port()) &&
  5385. + MatchesPath(StripTrailingWildcard(other.path()));
  5386. +}
  5387. +
  5388. +absl::optional<URLPattern> URLPattern::CreateIntersection(
  5389. + const URLPattern& other) const {
  5390. + // Easy case: Schemes don't overlap. Return nullopt.
  5391. + int intersection_schemes = URLPattern::SCHEME_NONE;
  5392. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  5393. + intersection_schemes = other.valid_schemes_;
  5394. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  5395. + intersection_schemes = valid_schemes_;
  5396. + else
  5397. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  5398. +
  5399. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  5400. + return absl::nullopt;
  5401. +
  5402. + {
  5403. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  5404. + // This can happen when either:
  5405. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  5406. + // - One of the patterns has match_all_urls() equal to true.
  5407. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  5408. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  5409. + // from the path, which could yield the incorrect result.
  5410. + const URLPattern* copy_source = nullptr;
  5411. + if (*this == other || other.match_all_urls())
  5412. + copy_source = this;
  5413. + else if (match_all_urls())
  5414. + copy_source = &other;
  5415. +
  5416. + if (copy_source) {
  5417. + // NOTE: equality checks don't take into account valid_schemes_, and
  5418. + // schemes can be different in the case of match_all_urls() as well, so
  5419. + // we can't always just return *copy_source.
  5420. + if (intersection_schemes == copy_source->valid_schemes_)
  5421. + return *copy_source;
  5422. + URLPattern result(intersection_schemes);
  5423. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  5424. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  5425. + return result;
  5426. + }
  5427. + }
  5428. +
  5429. + // No more easy cases. Go through component by component to find the patterns
  5430. + // that intersect.
  5431. +
  5432. + // Note: Alias the function type (rather than using auto) because
  5433. + // MatchesHost() is overloaded.
  5434. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  5435. +
  5436. + auto get_intersection = [this, &other](base::StringPiece own_str,
  5437. + base::StringPiece other_str,
  5438. + match_function_type match_function,
  5439. + base::StringPiece* out) {
  5440. + if ((this->*match_function)(other_str)) {
  5441. + *out = other_str;
  5442. + return true;
  5443. + }
  5444. + if ((other.*match_function)(own_str)) {
  5445. + *out = own_str;
  5446. + return true;
  5447. + }
  5448. + return false;
  5449. + };
  5450. +
  5451. + base::StringPiece scheme;
  5452. + base::StringPiece host;
  5453. + base::StringPiece port;
  5454. + base::StringPiece path;
  5455. + // If any pieces fail to overlap, then there is no intersection.
  5456. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  5457. + &scheme) ||
  5458. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  5459. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  5460. + &port) ||
  5461. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  5462. + return absl::nullopt;
  5463. + }
  5464. +
  5465. + // Only match subdomains if both patterns match subdomains.
  5466. + base::StringPiece subdomains;
  5467. + if (match_subdomains_ && other.match_subdomains_) {
  5468. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  5469. + // append '*' instead of '*.'.
  5470. + subdomains = host.empty() ? "*" : "*.";
  5471. + }
  5472. +
  5473. + base::StringPiece scheme_separator =
  5474. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  5475. +
  5476. + std::string pattern_str = base::StrCat(
  5477. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  5478. +
  5479. + URLPattern pattern(intersection_schemes);
  5480. + ParseResult result = pattern.Parse(pattern_str);
  5481. + // TODO(devlin): I don't think there's any way this should ever fail, but
  5482. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  5483. + // to a DCHECK in M72.
  5484. + CHECK_EQ(ParseResult::kSuccess, result);
  5485. +
  5486. + return pattern;
  5487. +}
  5488. +
  5489. +bool URLPattern::MatchesAnyScheme(
  5490. + const std::vector<std::string>& schemes) const {
  5491. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5492. + if (MatchesScheme(*i))
  5493. + return true;
  5494. + }
  5495. +
  5496. + return false;
  5497. +}
  5498. +
  5499. +bool URLPattern::MatchesAllSchemes(
  5500. + const std::vector<std::string>& schemes) const {
  5501. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5502. + if (!MatchesScheme(*i))
  5503. + return false;
  5504. + }
  5505. +
  5506. + return true;
  5507. +}
  5508. +
  5509. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  5510. + // Ignore hostname if scheme is file://.
  5511. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  5512. + return false;
  5513. +
  5514. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  5515. + return false;
  5516. +
  5517. + return true;
  5518. +}
  5519. +
  5520. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  5521. + return port_ == "*" || port_ == port;
  5522. +}
  5523. +
  5524. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  5525. + std::vector<std::string> result;
  5526. +
  5527. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  5528. + result.push_back(scheme_);
  5529. + return result;
  5530. + }
  5531. +
  5532. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5533. + if (MatchesScheme(kValidSchemes[i])) {
  5534. + result.push_back(kValidSchemes[i]);
  5535. + }
  5536. + }
  5537. +
  5538. + return result;
  5539. +}
  5540. +
  5541. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  5542. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  5543. + std::vector<URLPattern> result;
  5544. +
  5545. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  5546. + i != explicit_schemes.end(); ++i) {
  5547. + URLPattern temp = *this;
  5548. + temp.SetScheme(*i);
  5549. + temp.SetMatchAllURLs(false);
  5550. + result.push_back(temp);
  5551. + }
  5552. +
  5553. + return result;
  5554. +}
  5555. +
  5556. +// static
  5557. +const char* URLPattern::GetParseResultString(
  5558. + URLPattern::ParseResult parse_result) {
  5559. + return kParseResultMessages[static_cast<int>(parse_result)];
  5560. +}
  5561. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  5562. new file mode 100755
  5563. --- /dev/null
  5564. +++ b/components/user_scripts/common/url_pattern.h
  5565. @@ -0,0 +1,302 @@
  5566. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5567. +// Use of this source code is governed by a BSD-style license that can be
  5568. +// found in the LICENSE file.
  5569. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_H_
  5570. +#define USERSCRIPTS_COMMON_URL_PATTERN_H_
  5571. +
  5572. +#include <functional>
  5573. +#include <iosfwd>
  5574. +#include <string>
  5575. +#include <vector>
  5576. +
  5577. +#include "base/strings/string_piece.h"
  5578. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  5579. +
  5580. +class GURL;
  5581. +
  5582. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  5583. +// subset of URL syntax:
  5584. +//
  5585. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  5586. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  5587. +// 'chrome-extension' | 'filesystem'
  5588. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  5589. +// '*.' <anychar except '/' and '*'>+
  5590. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  5591. +// <path> := '/' <any chars>
  5592. +//
  5593. +// * Host is not used when the scheme is 'file'.
  5594. +// * The path can have embedded '*' characters which act as glob wildcards.
  5595. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  5596. +// a valid scheme (as specified by valid_schemes_).
  5597. +// * The '*' scheme pattern excludes file URLs.
  5598. +//
  5599. +// Examples of valid patterns:
  5600. +// - http://*/*
  5601. +// - http://*/foo*
  5602. +// - https://*.google.com/foo*bar
  5603. +// - file://monkey*
  5604. +// - http://127.0.0.1/*
  5605. +// - http://[2607:f8b0:4005:805::200e]/*
  5606. +//
  5607. +// Examples of invalid patterns:
  5608. +// - http://* -- path not specified
  5609. +// - http://*foo/bar -- * not allowed as substring of host component
  5610. +// - http://foo.*.bar/baz -- * must be first component
  5611. +// - http:/bar -- scheme separator not found
  5612. +// - foo://* -- invalid scheme
  5613. +// - chrome:// -- we don't support chrome internal URLs
  5614. +class URLPattern {
  5615. + public:
  5616. + // A collection of scheme bitmasks for use with valid_schemes.
  5617. + enum SchemeMasks {
  5618. + SCHEME_NONE = 0,
  5619. + SCHEME_HTTP = 1 << 0,
  5620. + SCHEME_HTTPS = 1 << 1,
  5621. + SCHEME_FILE = 1 << 2,
  5622. + SCHEME_FTP = 1 << 3,
  5623. + SCHEME_CHROMEUI = 1 << 4,
  5624. + SCHEME_EXTENSION = 1 << 5,
  5625. + SCHEME_FILESYSTEM = 1 << 6,
  5626. + SCHEME_WS = 1 << 7,
  5627. + SCHEME_WSS = 1 << 8,
  5628. + SCHEME_DATA = 1 << 9,
  5629. + SCHEME_URN = 1 << 10,
  5630. +
  5631. + // IMPORTANT!
  5632. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  5633. + // extension://, about:, etc. Because this has lots of security
  5634. + // implications, third-party extensions should usually not be able to get
  5635. + // access to URL patterns initialized this way. If there is a reason
  5636. + // for violating this general rule, document why this it safe.
  5637. + SCHEME_ALL = -1,
  5638. + };
  5639. +
  5640. + // Error codes returned from Parse().
  5641. + enum class ParseResult {
  5642. + kSuccess = 0,
  5643. + kMissingSchemeSeparator,
  5644. + kInvalidScheme,
  5645. + kWrongSchemeSeparator,
  5646. + kEmptyHost,
  5647. + kInvalidHostWildcard,
  5648. + kEmptyPath,
  5649. + kInvalidPort,
  5650. + kInvalidHost,
  5651. + kNumParseResults,
  5652. + };
  5653. +
  5654. + // The <all_urls> string pattern.
  5655. + static const char kAllUrlsPattern[];
  5656. +
  5657. + // Returns true if the given |scheme| is considered valid for extensions.
  5658. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  5659. +
  5660. + // Returns the mask for all schemes considered valid for extensions.
  5661. + static int GetValidSchemeMaskForExtensions();
  5662. +
  5663. + explicit URLPattern(int valid_schemes);
  5664. +
  5665. + // Convenience to construct a URLPattern from a string. If the string is not
  5666. + // known ahead of time, use Parse() instead, which returns success or failure.
  5667. + URLPattern(int valid_schemes, base::StringPiece pattern);
  5668. +
  5669. + URLPattern();
  5670. + URLPattern(const URLPattern& other);
  5671. + URLPattern(URLPattern&& other);
  5672. + ~URLPattern();
  5673. +
  5674. + URLPattern& operator=(const URLPattern& other);
  5675. + URLPattern& operator=(URLPattern&& other);
  5676. +
  5677. + bool operator<(const URLPattern& other) const;
  5678. + bool operator>(const URLPattern& other) const;
  5679. + bool operator==(const URLPattern& other) const;
  5680. +
  5681. + // Initializes this instance by parsing the provided string. Returns
  5682. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  5683. + // On failure, this instance will have some intermediate values and is in an
  5684. + // invalid state.
  5685. + ParseResult Parse(base::StringPiece pattern_str);
  5686. +
  5687. + // Gets the bitmask of valid schemes.
  5688. + int valid_schemes() const { return valid_schemes_; }
  5689. + void SetValidSchemes(int valid_schemes);
  5690. +
  5691. + // Gets the host the pattern matches. This can be an empty string if the
  5692. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  5693. + const std::string& host() const { return host_; }
  5694. + void SetHost(base::StringPiece host);
  5695. +
  5696. + // Gets whether to match subdomains of host().
  5697. + bool match_subdomains() const { return match_subdomains_; }
  5698. + void SetMatchSubdomains(bool val);
  5699. +
  5700. + // Gets the path the pattern matches with the leading slash. This can have
  5701. + // embedded asterisks which are interpreted using glob rules.
  5702. + const std::string& path() const { return path_; }
  5703. + void SetPath(base::StringPiece path);
  5704. +
  5705. + // Returns true if this pattern matches all (valid) urls.
  5706. + bool match_all_urls() const { return match_all_urls_; }
  5707. + void SetMatchAllURLs(bool val);
  5708. +
  5709. + // Sets the scheme for pattern matches. This can be a single '*' if the
  5710. + // pattern matches all valid schemes (as defined by the valid_schemes_
  5711. + // property). Returns false on failure (if the scheme is not valid).
  5712. + bool SetScheme(base::StringPiece scheme);
  5713. + // Note: You should use MatchesScheme() instead of this getter unless you
  5714. + // absolutely need the exact scheme. This is exposed for testing.
  5715. + const std::string& scheme() const { return scheme_; }
  5716. +
  5717. + // Returns true if the specified scheme can be used in this URL pattern, and
  5718. + // false otherwise. Uses valid_schemes_ to determine validity.
  5719. + bool IsValidScheme(base::StringPiece scheme) const;
  5720. +
  5721. + // Returns true if this instance matches the specified URL. Always returns
  5722. + // false for invalid URLs.
  5723. + bool MatchesURL(const GURL& test) const;
  5724. +
  5725. + // Returns true if this instance matches the specified security origin.
  5726. + bool MatchesSecurityOrigin(const GURL& test) const;
  5727. +
  5728. + // Returns true if |test| matches our scheme.
  5729. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  5730. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  5731. + // of the outer "filesystem:" part.
  5732. + bool MatchesScheme(base::StringPiece test) const;
  5733. +
  5734. + // Returns true if |test| matches our host.
  5735. + bool MatchesHost(base::StringPiece test) const;
  5736. + bool MatchesHost(const GURL& test) const;
  5737. +
  5738. + // Returns true if |test| matches our path.
  5739. + bool MatchesPath(base::StringPiece test) const;
  5740. +
  5741. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  5742. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  5743. + // matches all domains (e.g., *://*/*) will return true.
  5744. + // |private_filter| specifies whether private registries (like appspot.com)
  5745. + // should be considered; if included, patterns like *://*.appspot.com/* will
  5746. + // return true. By default, we exclude private registries (so *.appspot.com
  5747. + // returns false).
  5748. + // Note: This is an expensive method, and should be used sparingly!
  5749. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  5750. + // cached.
  5751. + bool MatchesEffectiveTld(
  5752. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  5753. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  5754. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  5755. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  5756. +
  5757. + // Returns true if the pattern only matches a single origin. The pattern may
  5758. + // include a path.
  5759. + bool MatchesSingleOrigin() const;
  5760. +
  5761. + // Sets the port. Returns false if the port is invalid.
  5762. + bool SetPort(base::StringPiece port);
  5763. + const std::string& port() const { return port_; }
  5764. +
  5765. + // Returns a string representing this instance.
  5766. + const std::string& GetAsString() const;
  5767. +
  5768. + // Determines whether there is a URL that would match this instance and
  5769. + // another instance. This method is symmetrical: Calling
  5770. + // other.OverlapsWith(this) would result in the same answer.
  5771. + bool OverlapsWith(const URLPattern& other) const;
  5772. +
  5773. + // Returns true if this pattern matches all possible URLs that |other| can
  5774. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5775. + bool Contains(const URLPattern& other) const;
  5776. +
  5777. + // Creates a new URLPattern that represents the intersection of this
  5778. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5779. + // For instance, given the patterns http://*.google.com/* and
  5780. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5781. + // NOTES:
  5782. + // - Though scheme intersections are supported, the serialization of
  5783. + // URLPatternSet does not record them. Be sure that this is safe for your
  5784. + // use cases.
  5785. + // - Path intersection is done on a best-effort basis. If one path clearly
  5786. + // contains another, it will be handled correctly, but this method does not
  5787. + // deal with cases like /*a* and /*b* (where technically the intersection
  5788. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5789. + absl::optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5790. +
  5791. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5792. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5793. + // wildcard scheme, then the returned set will contain one element that is
  5794. + // equivalent to this instance.
  5795. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5796. +
  5797. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5798. + if (a.match_all_urls_ && b.match_all_urls_)
  5799. + return false;
  5800. + return a.host_.compare(b.host_) < 0;
  5801. + }
  5802. +
  5803. + // Used for origin comparisons in a std::set.
  5804. + class EffectiveHostCompareFunctor {
  5805. + public:
  5806. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5807. + return EffectiveHostCompare(a, b);
  5808. + }
  5809. + };
  5810. +
  5811. + // Get an error string for a ParseResult.
  5812. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5813. +
  5814. + private:
  5815. + // Returns true if any of the |schemes| items matches our scheme.
  5816. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5817. +
  5818. + // Returns true if all of the |schemes| items matches our scheme.
  5819. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5820. +
  5821. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5822. +
  5823. + // Returns true if our port matches the |port| pattern (it may be "*").
  5824. + bool MatchesPortPattern(base::StringPiece port) const;
  5825. +
  5826. + // If the URLPattern contains a wildcard scheme, returns a list of
  5827. + // equivalent literal schemes, otherwise returns the current scheme.
  5828. + std::vector<std::string> GetExplicitSchemes() const;
  5829. +
  5830. + // A bitmask containing the schemes which are considered valid for this
  5831. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5832. + // scheme.
  5833. + int valid_schemes_;
  5834. +
  5835. + // True if this is a special-case "<all_urls>" pattern.
  5836. + bool match_all_urls_;
  5837. +
  5838. + // The scheme for the pattern.
  5839. + std::string scheme_;
  5840. +
  5841. + // The host without any leading "*" components.
  5842. + std::string host_;
  5843. +
  5844. + // Whether we should match subdomains of the host. This is true if the first
  5845. + // component of the pattern's host was "*".
  5846. + bool match_subdomains_;
  5847. +
  5848. + // The port.
  5849. + std::string port_;
  5850. +
  5851. + // The path to match. This is everything after the host of the URL, or
  5852. + // everything after the scheme in the case of file:// URLs.
  5853. + std::string path_;
  5854. +
  5855. + // The path with "?" and "\" characters escaped for use with the
  5856. + // MatchPattern() function.
  5857. + std::string path_escaped_;
  5858. +
  5859. + // A string representing this URLPattern.
  5860. + mutable std::string spec_;
  5861. +};
  5862. +
  5863. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5864. +
  5865. +typedef std::vector<URLPattern> URLPatternList;
  5866. +
  5867. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_H_
  5868. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5869. new file mode 100755
  5870. --- /dev/null
  5871. +++ b/components/user_scripts/common/url_pattern_set.cc
  5872. @@ -0,0 +1,335 @@
  5873. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5874. +// Use of this source code is governed by a BSD-style license that can be
  5875. +// found in the LICENSE file.
  5876. +
  5877. +#include "url_pattern_set.h"
  5878. +
  5879. +#include <iterator>
  5880. +#include <ostream>
  5881. +
  5882. +#include "base/containers/contains.h"
  5883. +#include "base/logging.h"
  5884. +#include "base/stl_util.h"
  5885. +#include "base/values.h"
  5886. +#include "error_utils.h"
  5887. +#include "url_pattern.h"
  5888. +#include "url/gurl.h"
  5889. +#include "url/origin.h"
  5890. +#include "url/url_constants.h"
  5891. +#include "user_scripts_features.h"
  5892. +
  5893. +namespace user_scripts {
  5894. +
  5895. +namespace {
  5896. +
  5897. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5898. +
  5899. +} // namespace
  5900. +
  5901. +// static
  5902. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5903. + const URLPatternSet& set2) {
  5904. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5905. + set1.patterns_, set2.patterns_));
  5906. +}
  5907. +
  5908. +// static
  5909. +URLPatternSet URLPatternSet::CreateIntersection(
  5910. + const URLPatternSet& set1,
  5911. + const URLPatternSet& set2,
  5912. + IntersectionBehavior intersection_behavior) {
  5913. + // Note: leverage return value optimization; always return the same object.
  5914. + URLPatternSet result;
  5915. +
  5916. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5917. + // String comparison just relies on STL set behavior, which looks at the
  5918. + // string representation.
  5919. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5920. + set1.patterns_, set2.patterns_));
  5921. + return result;
  5922. + }
  5923. +
  5924. + // Look for a semantic intersection.
  5925. +
  5926. + // Step 1: Iterate over each set. Find any patterns that are completely
  5927. + // contained by the other (thus being necessarily present in any intersection)
  5928. + // and add them, collecting the others in a set of unique items.
  5929. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5930. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5931. + // const, this should be safe.
  5932. + std::vector<const URLPattern*> unique_set1;
  5933. + for (const URLPattern& pattern : set1) {
  5934. + if (set2.ContainsPattern(pattern))
  5935. + result.patterns_.insert(pattern);
  5936. + else
  5937. + unique_set1.push_back(&pattern);
  5938. + }
  5939. + std::vector<const URLPattern*> unique_set2;
  5940. + for (const URLPattern& pattern : set2) {
  5941. + if (set1.ContainsPattern(pattern))
  5942. + result.patterns_.insert(pattern);
  5943. + else
  5944. + unique_set2.push_back(&pattern);
  5945. + }
  5946. +
  5947. + // If we're just looking for patterns contained by both, we're done.
  5948. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5949. + return result;
  5950. +
  5951. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5952. +
  5953. + // Step 2: Iterate over all the unique patterns and find the intersections
  5954. + // they have with the other patterns.
  5955. + for (const auto* pattern : unique_set1) {
  5956. + for (const auto* pattern2 : unique_set2) {
  5957. + absl::optional<URLPattern> intersection =
  5958. + pattern->CreateIntersection(*pattern2);
  5959. + if (intersection)
  5960. + result.patterns_.insert(std::move(*intersection));
  5961. + }
  5962. + }
  5963. +
  5964. + return result;
  5965. +}
  5966. +
  5967. +// static
  5968. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  5969. + const URLPatternSet& set2) {
  5970. + return URLPatternSet(
  5971. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  5972. +}
  5973. +
  5974. +// static
  5975. +URLPatternSet URLPatternSet::CreateUnion(
  5976. + const std::vector<URLPatternSet>& sets) {
  5977. + URLPatternSet result;
  5978. + if (sets.empty())
  5979. + return result;
  5980. +
  5981. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  5982. + //
  5983. + // Do the first merge step into a working set so that we don't mutate any of
  5984. + // the input.
  5985. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  5986. + // clean that up.
  5987. + std::vector<URLPatternSet> working;
  5988. + for (size_t i = 0; i < sets.size(); i += 2) {
  5989. + if (i + 1 < sets.size())
  5990. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  5991. + else
  5992. + working.push_back(sets[i].Clone());
  5993. + }
  5994. +
  5995. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  5996. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  5997. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  5998. + working[i].patterns_.swap(u.patterns_);
  5999. + }
  6000. + }
  6001. +
  6002. + result.patterns_.swap(working[0].patterns_);
  6003. + return result;
  6004. +}
  6005. +
  6006. +URLPatternSet::URLPatternSet() = default;
  6007. +
  6008. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  6009. +
  6010. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  6011. + : patterns_(patterns) {}
  6012. +
  6013. +URLPatternSet::~URLPatternSet() = default;
  6014. +
  6015. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  6016. +
  6017. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  6018. + return patterns_ == other.patterns_;
  6019. +}
  6020. +
  6021. +std::ostream& operator<<(std::ostream& out,
  6022. + const URLPatternSet& url_pattern_set) {
  6023. + out << "{ ";
  6024. +
  6025. + auto iter = url_pattern_set.patterns().cbegin();
  6026. + if (!url_pattern_set.patterns().empty()) {
  6027. + out << *iter;
  6028. + ++iter;
  6029. + }
  6030. +
  6031. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  6032. + out << ", " << *iter;
  6033. +
  6034. + if (!url_pattern_set.patterns().empty())
  6035. + out << " ";
  6036. +
  6037. + out << "}";
  6038. + return out;
  6039. +}
  6040. +
  6041. +URLPatternSet URLPatternSet::Clone() const {
  6042. + return URLPatternSet(patterns_);
  6043. +}
  6044. +
  6045. +bool URLPatternSet::is_empty() const {
  6046. + return patterns_.empty();
  6047. +}
  6048. +
  6049. +size_t URLPatternSet::size() const {
  6050. + return patterns_.size();
  6051. +}
  6052. +
  6053. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  6054. + return patterns_.insert(pattern).second;
  6055. +}
  6056. +
  6057. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  6058. + patterns_.insert(set.patterns().begin(),
  6059. + set.patterns().end());
  6060. +}
  6061. +
  6062. +void URLPatternSet::ClearPatterns() {
  6063. + patterns_.clear();
  6064. +}
  6065. +
  6066. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  6067. + if (origin.is_empty())
  6068. + return false;
  6069. + const url::Origin real_origin = url::Origin::Create(origin);
  6070. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(
  6071. + origin.DeprecatedGetOriginAsURL())));
  6072. + URLPattern origin_pattern(valid_schemes);
  6073. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  6074. + if (origin_pattern.Parse(origin.spec()) !=
  6075. + URLPattern::ParseResult::kSuccess) {
  6076. + return false;
  6077. + }
  6078. + origin_pattern.SetPath("/*");
  6079. + return AddPattern(origin_pattern);
  6080. +}
  6081. +
  6082. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  6083. + for (auto it = other.begin(); it != other.end(); ++it) {
  6084. + if (!ContainsPattern(*it))
  6085. + return false;
  6086. + }
  6087. +
  6088. + return true;
  6089. +}
  6090. +
  6091. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  6092. + for (auto it = begin(); it != end(); ++it) {
  6093. + if (it->Contains(pattern))
  6094. + return true;
  6095. + }
  6096. + return false;
  6097. +}
  6098. +
  6099. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  6100. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  6101. + ++pattern) {
  6102. + if (pattern->MatchesURL(url)) {
  6103. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6104. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  6105. +
  6106. + return true;
  6107. + }
  6108. + }
  6109. +
  6110. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6111. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  6112. +
  6113. + return false;
  6114. +}
  6115. +
  6116. +bool URLPatternSet::MatchesAllURLs() const {
  6117. + for (auto host = begin(); host != end(); ++host) {
  6118. + if (host->match_all_urls() ||
  6119. + (host->match_subdomains() && host->host().empty()))
  6120. + return true;
  6121. + }
  6122. + return false;
  6123. +}
  6124. +
  6125. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  6126. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  6127. + ++pattern) {
  6128. + if (pattern->MatchesSecurityOrigin(origin))
  6129. + return true;
  6130. + }
  6131. +
  6132. + return false;
  6133. +}
  6134. +
  6135. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  6136. + // Two extension extents overlap if there is any one URL that would match at
  6137. + // least one pattern in each of the extents.
  6138. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6139. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  6140. + ++j) {
  6141. + if (i->OverlapsWith(*j))
  6142. + return true;
  6143. + }
  6144. + }
  6145. +
  6146. + return false;
  6147. +}
  6148. +
  6149. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  6150. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  6151. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6152. + base::Value pattern_str_value(i->GetAsString());
  6153. + if (!base::Contains(value->GetList(), pattern_str_value))
  6154. + value->Append(std::move(pattern_str_value));
  6155. + }
  6156. + return value;
  6157. +}
  6158. +
  6159. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  6160. + int valid_schemes,
  6161. + bool allow_file_access,
  6162. + std::string* error) {
  6163. + ClearPatterns();
  6164. + for (size_t i = 0; i < patterns.size(); ++i) {
  6165. + URLPattern pattern(valid_schemes);
  6166. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  6167. + if (error) {
  6168. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  6169. + patterns[i]);
  6170. + } else {
  6171. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  6172. + }
  6173. + return false;
  6174. + }
  6175. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  6176. + pattern.SetValidSchemes(
  6177. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  6178. + }
  6179. + AddPattern(pattern);
  6180. + }
  6181. + return true;
  6182. +}
  6183. +
  6184. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  6185. + const {
  6186. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  6187. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6188. + value->push_back(i->GetAsString());
  6189. + }
  6190. + return value;
  6191. +}
  6192. +
  6193. +bool URLPatternSet::Populate(const base::ListValue& value,
  6194. + int valid_schemes,
  6195. + bool allow_file_access,
  6196. + std::string* error) {
  6197. + std::vector<std::string> patterns;
  6198. + for (size_t i = 0; i < value.GetList().size(); ++i) {
  6199. + std::string item;
  6200. + if (!value.GetString(i, &item))
  6201. + return false;
  6202. + patterns.push_back(item);
  6203. + }
  6204. + return Populate(patterns, valid_schemes, allow_file_access, error);
  6205. +}
  6206. +
  6207. +} // namespace extensions
  6208. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  6209. new file mode 100755
  6210. --- /dev/null
  6211. +++ b/components/user_scripts/common/url_pattern_set.h
  6212. @@ -0,0 +1,161 @@
  6213. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6214. +// Use of this source code is governed by a BSD-style license that can be
  6215. +// found in the LICENSE file.
  6216. +
  6217. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6218. +#define USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6219. +
  6220. +#include <stddef.h>
  6221. +
  6222. +#include <iosfwd>
  6223. +#include <memory>
  6224. +#include <set>
  6225. +
  6226. +#include "base/macros.h"
  6227. +#include "url_pattern.h"
  6228. +
  6229. +class GURL;
  6230. +
  6231. +namespace base {
  6232. +class ListValue;
  6233. +class Value;
  6234. +}
  6235. +
  6236. +namespace user_scripts {
  6237. +
  6238. +// Represents the set of URLs an extension uses for web content.
  6239. +class URLPatternSet {
  6240. + public:
  6241. + typedef std::set<URLPattern>::const_iterator const_iterator;
  6242. + typedef std::set<URLPattern>::iterator iterator;
  6243. +
  6244. + // Returns |set1| - |set2|.
  6245. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  6246. + const URLPatternSet& set2);
  6247. +
  6248. + enum class IntersectionBehavior {
  6249. + // For the following descriptions, consider the two URLPatternSets:
  6250. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  6251. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  6252. + // "*://chromium.org/*"}
  6253. +
  6254. + // Only includes patterns that are exactly in both sets. The intersection of
  6255. + // the two sets above is {"https://example.com/*"}, since that is the only
  6256. + // pattern that appears exactly in each.
  6257. + kStringComparison,
  6258. +
  6259. + // Includes patterns that are effectively contained by both sets. The
  6260. + // intersection of the two sets above is
  6261. + // {
  6262. + // "https://example.com/*" (contained exactly by each set)
  6263. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6264. + // subset of https://*.google.com/* in set 1)
  6265. + // }
  6266. + kPatternsContainedByBoth,
  6267. +
  6268. + // Includes patterns that are contained by both sets and creates new
  6269. + // patterns to represent the intersection of any others. The intersection of
  6270. + // the two sets above is
  6271. + // {
  6272. + // "https://example.com/*" (contained exactly by each set)
  6273. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6274. + // subset of https://*.google.com/* in set 1)
  6275. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  6276. + // *://chromium.org/*" in set 2).
  6277. + // }
  6278. + // Note that this is the most computationally expensive - potentially
  6279. + // O(n^2) - since it can require comparing each pattern in one set to every
  6280. + // pattern in the other set.
  6281. + kDetailed,
  6282. + };
  6283. +
  6284. + // Returns the intersection of |set1| and |set2| according to
  6285. + // |intersection_behavior|.
  6286. + static URLPatternSet CreateIntersection(
  6287. + const URLPatternSet& set1,
  6288. + const URLPatternSet& set2,
  6289. + IntersectionBehavior intersection_behavior);
  6290. +
  6291. + // Returns the union of |set1| and |set2|.
  6292. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  6293. + const URLPatternSet& set2);
  6294. +
  6295. + // Returns the union of all sets in |sets|.
  6296. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  6297. +
  6298. + URLPatternSet();
  6299. + URLPatternSet(URLPatternSet&& rhs);
  6300. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  6301. + ~URLPatternSet();
  6302. +
  6303. + URLPatternSet& operator=(URLPatternSet&& rhs);
  6304. + bool operator==(const URLPatternSet& rhs) const;
  6305. +
  6306. + bool is_empty() const;
  6307. + size_t size() const;
  6308. + const std::set<URLPattern>& patterns() const { return patterns_; }
  6309. + const_iterator begin() const { return patterns_.begin(); }
  6310. + const_iterator end() const { return patterns_.end(); }
  6311. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  6312. +
  6313. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  6314. + // constructor to avoid accidental/unnecessary copies.
  6315. + URLPatternSet Clone() const;
  6316. +
  6317. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  6318. + // false if the pattern was already in the set.
  6319. + bool AddPattern(const URLPattern& pattern);
  6320. +
  6321. + // Adds all patterns from |set| into this.
  6322. + void AddPatterns(const URLPatternSet& set);
  6323. +
  6324. + void ClearPatterns();
  6325. +
  6326. + // Adds a pattern based on |origin| to the set.
  6327. + bool AddOrigin(int valid_schemes, const GURL& origin);
  6328. +
  6329. + // Returns true if every URL that matches |set| is matched by this. In other
  6330. + // words, if every pattern in |set| is encompassed by a pattern in this.
  6331. + bool Contains(const URLPatternSet& set) const;
  6332. +
  6333. + // Returns true if any pattern in this set encompasses |pattern|.
  6334. + bool ContainsPattern(const URLPattern& pattern) const;
  6335. +
  6336. + // Test if the extent contains a URL.
  6337. + bool MatchesURL(const GURL& url) const;
  6338. +
  6339. + // Test if the extent matches all URLs (for example, <all_urls>).
  6340. + bool MatchesAllURLs() const;
  6341. +
  6342. + bool MatchesSecurityOrigin(const GURL& origin) const;
  6343. +
  6344. + // Returns true if there is a single URL that would be in two extents.
  6345. + bool OverlapsWith(const URLPatternSet& other) const;
  6346. +
  6347. + // Converts to and from Value for serialization to preferences.
  6348. + std::unique_ptr<base::ListValue> ToValue() const;
  6349. + bool Populate(const base::ListValue& value,
  6350. + int valid_schemes,
  6351. + bool allow_file_access,
  6352. + std::string* error);
  6353. +
  6354. + // Converts to and from a vector of strings.
  6355. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  6356. + bool Populate(const std::vector<std::string>& patterns,
  6357. + int valid_schemes,
  6358. + bool allow_file_access,
  6359. + std::string* error);
  6360. +
  6361. + private:
  6362. + // The list of URL patterns that comprise the extent.
  6363. + std::set<URLPattern> patterns_;
  6364. +
  6365. + DISALLOW_COPY_AND_ASSIGN(URLPatternSet);
  6366. +};
  6367. +
  6368. +std::ostream& operator<<(std::ostream& out,
  6369. + const URLPatternSet& url_pattern_set);
  6370. +
  6371. +} // namespace extensions
  6372. +
  6373. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6374. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  6375. new file mode 100755
  6376. --- /dev/null
  6377. +++ b/components/user_scripts/common/user_script.cc
  6378. @@ -0,0 +1,325 @@
  6379. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6380. +// Use of this source code is governed by a BSD-style license that can be
  6381. +// found in the LICENSE file.
  6382. +
  6383. +#include "user_script.h"
  6384. +
  6385. +#include <stddef.h>
  6386. +#include <stdint.h>
  6387. +
  6388. +#include <memory>
  6389. +#include <utility>
  6390. +
  6391. +#include "base/atomic_sequence_num.h"
  6392. +#include "base/command_line.h"
  6393. +#include "base/pickle.h"
  6394. +#include "base/strings/pattern.h"
  6395. +#include "base/strings/string_util.h"
  6396. +#include "user_scripts_features.h"
  6397. +
  6398. +namespace {
  6399. +
  6400. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  6401. +// from multiple threads.
  6402. +base::AtomicSequenceNumber g_user_script_id_generator;
  6403. +
  6404. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  6405. + const GURL& url) {
  6406. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  6407. + if (base::MatchPattern(url.spec(), *glob))
  6408. + return true;
  6409. + }
  6410. +
  6411. + return false;
  6412. +}
  6413. +
  6414. +} // namespace
  6415. +
  6416. +namespace user_scripts {
  6417. +
  6418. +// The bitmask for valid user script injectable schemes used by URLPattern.
  6419. +enum {
  6420. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  6421. + URLPattern::SCHEME_HTTP |
  6422. + URLPattern::SCHEME_HTTPS
  6423. + //| URLPattern::SCHEME_FILE |
  6424. + //URLPattern::SCHEME_FTP
  6425. +};
  6426. +
  6427. +// static
  6428. +const char UserScript::kFileExtension[] = ".user.js";
  6429. +
  6430. +// static
  6431. +int UserScript::GenerateUserScriptID() {
  6432. + return g_user_script_id_generator.GetNext();
  6433. +}
  6434. +
  6435. +bool UserScript::IsURLUserScript(const GURL& url,
  6436. + const std::string& mime_type) {
  6437. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  6438. + base::CompareCase::INSENSITIVE_ASCII) &&
  6439. + mime_type != "text/html";
  6440. +}
  6441. +
  6442. +// static
  6443. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  6444. + if (canExecuteScriptEverywhere)
  6445. + return URLPattern::SCHEME_ALL;
  6446. + int valid_schemes = kValidUserScriptSchemes;
  6447. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  6448. + // switches::kExtensionsOnChromeURLs)) {
  6449. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  6450. + // }
  6451. + return valid_schemes;
  6452. +}
  6453. +
  6454. +UserScript::File::File(const base::FilePath& extension_root,
  6455. + const base::FilePath& relative_path,
  6456. + const GURL& url)
  6457. + : extension_root_(extension_root),
  6458. + relative_path_(relative_path),
  6459. + url_(url) {
  6460. +}
  6461. +
  6462. +UserScript::File::File() {}
  6463. +
  6464. +UserScript::File::File(const File& other)
  6465. + : extension_root_(other.extension_root_),
  6466. + relative_path_(other.relative_path_),
  6467. + url_(other.url_),
  6468. + external_content_(other.external_content_),
  6469. + content_(other.content_),
  6470. + key_(other.key_) {}
  6471. +
  6472. +UserScript::File::~File() {}
  6473. +
  6474. +UserScript::UserScript() = default;
  6475. +UserScript::~UserScript() = default;
  6476. +
  6477. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  6478. + url_set_.AddPattern(pattern);
  6479. +}
  6480. +
  6481. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  6482. + exclude_url_set_.AddPattern(pattern);
  6483. +}
  6484. +
  6485. +bool UserScript::MatchesURL(const GURL& url) const {
  6486. + // exclude schemas not valid
  6487. + URLPattern pattern(kValidUserScriptSchemes);
  6488. + pattern.Parse(url.spec());
  6489. + if (!pattern.IsValidScheme(pattern.scheme()))
  6490. + return false;
  6491. +
  6492. + if (!url_set_.is_empty()) {
  6493. + if (!url_set_.MatchesURL(url)) {
  6494. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6495. + LOG(INFO) << "UserScripts: No Match for url_set";
  6496. + return false;
  6497. + }
  6498. + }
  6499. +
  6500. + if (!exclude_url_set_.is_empty()) {
  6501. + if (exclude_url_set_.MatchesURL(url)) {
  6502. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6503. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  6504. + return false;
  6505. + }
  6506. + }
  6507. +
  6508. + if (!globs_.empty()) {
  6509. + if (!UrlMatchesGlobs(&globs_, url)) {
  6510. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6511. + LOG(INFO) << "UserScripts: No Match for globs";
  6512. + return false;
  6513. + }
  6514. + }
  6515. +
  6516. + if (!exclude_globs_.empty()) {
  6517. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  6518. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6519. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  6520. + return false;
  6521. + }
  6522. + }
  6523. +
  6524. + return true;
  6525. +}
  6526. +
  6527. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  6528. + bool is_subframe) const {
  6529. + if (is_subframe && !match_all_frames())
  6530. + return false;
  6531. +
  6532. + return MatchesURL(effective_document_url);
  6533. +}
  6534. +
  6535. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  6536. + pickle->WriteString(url_.spec());
  6537. + // Do not write path. It's not needed in the renderer.
  6538. + // Do not write content. It will be serialized by other means.
  6539. +}
  6540. +
  6541. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  6542. + base::PickleIterator* iter) {
  6543. + // Read the url from the pickle.
  6544. + std::string url;
  6545. + CHECK(iter->ReadString(&url));
  6546. + set_url(GURL(url));
  6547. +}
  6548. +
  6549. +void UserScript::Pickle(base::Pickle* pickle) const {
  6550. + // Write the simple types to the pickle.
  6551. + pickle->WriteInt(run_location());
  6552. + pickle->WriteInt(user_script_id_);
  6553. + pickle->WriteString(name_);
  6554. + pickle->WriteBool(emulate_greasemonkey());
  6555. + pickle->WriteBool(match_all_frames());
  6556. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  6557. + pickle->WriteBool(is_incognito_enabled());
  6558. +
  6559. + PickleHostID(pickle, host_id_);
  6560. + pickle->WriteInt(consumer_instance_type());
  6561. + PickleGlobs(pickle, globs_);
  6562. + PickleGlobs(pickle, exclude_globs_);
  6563. + PickleURLPatternSet(pickle, url_set_);
  6564. + PickleURLPatternSet(pickle, exclude_url_set_);
  6565. + PickleScripts(pickle, js_scripts_);
  6566. + PickleScripts(pickle, css_scripts_);
  6567. +}
  6568. +
  6569. +void UserScript::PickleGlobs(base::Pickle* pickle,
  6570. + const std::vector<std::string>& globs) const {
  6571. + pickle->WriteUInt32(globs.size());
  6572. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  6573. + pickle->WriteString(*glob);
  6574. + }
  6575. +}
  6576. +
  6577. +void UserScript::PickleHostID(base::Pickle* pickle,
  6578. + const HostID& host_id) const {
  6579. + pickle->WriteInt(host_id.type());
  6580. + pickle->WriteString(host_id.id());
  6581. +}
  6582. +
  6583. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  6584. + const URLPatternSet& pattern_list) const {
  6585. + pickle->WriteUInt32(pattern_list.patterns().size());
  6586. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  6587. + ++pattern) {
  6588. + pickle->WriteInt(pattern->valid_schemes());
  6589. + pickle->WriteString(pattern->GetAsString());
  6590. + }
  6591. +}
  6592. +
  6593. +void UserScript::PickleScripts(base::Pickle* pickle,
  6594. + const FileList& scripts) const {
  6595. + pickle->WriteUInt32(scripts.size());
  6596. + for (const std::unique_ptr<File>& file : scripts)
  6597. + file->Pickle(pickle);
  6598. +}
  6599. +
  6600. +void UserScript::Unpickle(const base::Pickle& pickle,
  6601. + base::PickleIterator* iter) {
  6602. + // Read the run location.
  6603. + int run_location = 0;
  6604. + CHECK(iter->ReadInt(&run_location));
  6605. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  6606. + run_location_ = static_cast<RunLocation>(run_location);
  6607. +
  6608. + CHECK(iter->ReadInt(&user_script_id_));
  6609. + CHECK(iter->ReadString(&name_));
  6610. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  6611. + CHECK(iter->ReadBool(&match_all_frames_));
  6612. + int match_origin_as_fallback_int = 0;
  6613. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  6614. + match_origin_as_fallback_ =
  6615. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  6616. + CHECK(iter->ReadBool(&incognito_enabled_));
  6617. +
  6618. + UnpickleHostID(pickle, iter, &host_id_);
  6619. +
  6620. + int consumer_instance_type = 0;
  6621. + CHECK(iter->ReadInt(&consumer_instance_type));
  6622. + consumer_instance_type_ =
  6623. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  6624. +
  6625. + UnpickleGlobs(pickle, iter, &globs_);
  6626. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  6627. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  6628. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  6629. + UnpickleScripts(pickle, iter, &js_scripts_);
  6630. + UnpickleScripts(pickle, iter, &css_scripts_);
  6631. +}
  6632. +
  6633. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  6634. + base::PickleIterator* iter,
  6635. + std::vector<std::string>* globs) {
  6636. + uint32_t num_globs = 0;
  6637. + CHECK(iter->ReadUInt32(&num_globs));
  6638. + globs->clear();
  6639. + for (uint32_t i = 0; i < num_globs; ++i) {
  6640. + std::string glob;
  6641. + CHECK(iter->ReadString(&glob));
  6642. + globs->push_back(glob);
  6643. + }
  6644. +}
  6645. +
  6646. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  6647. + base::PickleIterator* iter,
  6648. + HostID* host_id) {
  6649. + int type = 0;
  6650. + std::string id;
  6651. + CHECK(iter->ReadInt(&type));
  6652. + CHECK(iter->ReadString(&id));
  6653. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  6654. +}
  6655. +
  6656. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  6657. + base::PickleIterator* iter,
  6658. + URLPatternSet* pattern_list) {
  6659. + uint32_t num_patterns = 0;
  6660. + CHECK(iter->ReadUInt32(&num_patterns));
  6661. +
  6662. + pattern_list->ClearPatterns();
  6663. + for (uint32_t i = 0; i < num_patterns; ++i) {
  6664. + int valid_schemes;
  6665. + CHECK(iter->ReadInt(&valid_schemes));
  6666. +
  6667. + std::string pattern_str;
  6668. + CHECK(iter->ReadString(&pattern_str));
  6669. +
  6670. + URLPattern pattern(kValidUserScriptSchemes);
  6671. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  6672. + CHECK(URLPattern::ParseResult::kSuccess == result)
  6673. + << URLPattern::GetParseResultString(result) << " "
  6674. + << pattern_str.c_str();
  6675. +
  6676. + pattern.SetValidSchemes(valid_schemes);
  6677. + pattern_list->AddPattern(pattern);
  6678. + }
  6679. +}
  6680. +
  6681. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  6682. + base::PickleIterator* iter,
  6683. + FileList* scripts) {
  6684. + uint32_t num_files = 0;
  6685. + CHECK(iter->ReadUInt32(&num_files));
  6686. + scripts->clear();
  6687. + for (uint32_t i = 0; i < num_files; ++i) {
  6688. + std::unique_ptr<File> file(new File());
  6689. + file->Unpickle(pickle, iter);
  6690. + scripts->push_back(std::move(file));
  6691. + }
  6692. +}
  6693. +
  6694. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  6695. + : id(id), host_id(host_id) {}
  6696. +
  6697. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  6698. +
  6699. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  6700. + return a.id < b.id;
  6701. +}
  6702. +
  6703. +} // namespace extensions
  6704. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  6705. new file mode 100755
  6706. --- /dev/null
  6707. +++ b/components/user_scripts/common/user_script.h
  6708. @@ -0,0 +1,403 @@
  6709. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6710. +// Use of this source code is governed by a BSD-style license that can be
  6711. +// found in the LICENSE file.
  6712. +
  6713. +#ifndef USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6714. +#define USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6715. +
  6716. +#include <memory>
  6717. +#include <string>
  6718. +#include <vector>
  6719. +
  6720. +#include "base/files/file_path.h"
  6721. +#include "base/strings/string_piece.h"
  6722. +#include "script_constants.h"
  6723. +#include "host_id.h"
  6724. +#include "url_pattern.h"
  6725. +#include "url_pattern_set.h"
  6726. +#include "url/gurl.h"
  6727. +
  6728. +namespace base {
  6729. +class Pickle;
  6730. +class PickleIterator;
  6731. +}
  6732. +
  6733. +namespace user_scripts {
  6734. +
  6735. +// Represents a user script, either a standalone one, or one that is part of an
  6736. +// extension.
  6737. +class UserScript {
  6738. + public:
  6739. + // The file extension for standalone user scripts.
  6740. + static const char kFileExtension[];
  6741. +
  6742. + static int GenerateUserScriptID();
  6743. +
  6744. + // Check if a URL should be treated as a user script and converted to an
  6745. + // extension.
  6746. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  6747. +
  6748. + // Get the valid user script schemes for the current process. If
  6749. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6750. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6751. +
  6752. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6753. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6754. + // The type of injected script.
  6755. + enum InjectionType {
  6756. + // A content script specified in the extension's manifest.
  6757. + CONTENT_SCRIPT,
  6758. + // A script injected via, e.g. tabs.executeScript().
  6759. + //PROGRAMMATIC_SCRIPT
  6760. + };
  6761. + // The last type of injected script; used for enum verification in IPC.
  6762. + // Update this if you add more injected script types!
  6763. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6764. +
  6765. + // Locations that user scripts can be run inside the document.
  6766. + // The three run locations must strictly follow each other in both load order
  6767. + // (i.e., start *always* comes before end) and numerically, as we use
  6768. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6769. + enum RunLocation {
  6770. + UNDEFINED,
  6771. + DOCUMENT_START, // After the documentElement is created, but before
  6772. + // anything else happens.
  6773. + DOCUMENT_END, // After the entire document is parsed. Same as
  6774. + // DOMContentLoaded.
  6775. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6776. + // is "idle". Currently this uses the simple heuristic of:
  6777. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6778. + // particular injection point is guaranteed.
  6779. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6780. + // reasons, and was executed at a later time.
  6781. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6782. + // IPC in the browser process.
  6783. + RUN_LOCATION_LAST // Leave this as the last item.
  6784. + };
  6785. +
  6786. + // Holds script file info.
  6787. + class File {
  6788. + public:
  6789. + File(const base::FilePath& extension_root,
  6790. + const base::FilePath& relative_path,
  6791. + const GURL& url);
  6792. + File();
  6793. + File(const File& other);
  6794. + ~File();
  6795. +
  6796. + const base::FilePath& extension_root() const { return extension_root_; }
  6797. + const base::FilePath& relative_path() const { return relative_path_; }
  6798. +
  6799. + const GURL& url() const { return url_; }
  6800. + void set_url(const GURL& url) { url_ = url; }
  6801. +
  6802. + // If external_content_ is set returns it as content otherwise it returns
  6803. + // content_
  6804. + const base::StringPiece GetContent() const {
  6805. + if (external_content_.data())
  6806. + return external_content_;
  6807. + else
  6808. + return content_;
  6809. + }
  6810. + void set_external_content(const base::StringPiece& content) {
  6811. + external_content_ = content;
  6812. + }
  6813. + void set_content(const base::StringPiece& content) {
  6814. + content_.assign(content.begin(), content.end());
  6815. + }
  6816. +
  6817. + const std::string& key() const { return key_; }
  6818. + void set_key(const std::string& key) {
  6819. + key_ = key;
  6820. + }
  6821. +
  6822. + // Serialization support. The content and FilePath members will not be
  6823. + // serialized!
  6824. + void Pickle(base::Pickle* pickle) const;
  6825. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6826. +
  6827. + private:
  6828. + // Where the script file lives on the disk. We keep the path split so that
  6829. + // it can be localized at will.
  6830. + base::FilePath extension_root_;
  6831. + base::FilePath relative_path_;
  6832. +
  6833. + // The url to this script file.
  6834. + GURL url_;
  6835. +
  6836. + // The script content. It can be set to either loaded_content_ or
  6837. + // externally allocated string.
  6838. + base::StringPiece external_content_;
  6839. +
  6840. + // Set when the content is loaded by LoadContent
  6841. + std::string content_;
  6842. +
  6843. + std::string key_;
  6844. + };
  6845. +
  6846. + using FileList = std::vector<std::unique_ptr<File>>;
  6847. +
  6848. + // Type of a API consumer instance that user scripts will be injected on.
  6849. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6850. +
  6851. + // Constructor. Default the run location to document end, which is like
  6852. + // Greasemonkey and probably more useful for typical scripts.
  6853. + UserScript();
  6854. + ~UserScript();
  6855. +
  6856. + // Performs a copy of all fields except file contents.
  6857. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6858. +
  6859. + const std::string& name_space() const { return name_space_; }
  6860. + void set_name_space(const std::string& name_space) {
  6861. + name_space_ = name_space;
  6862. + }
  6863. +
  6864. + const std::string& name() const { return name_; }
  6865. + void set_name(const std::string& name) { name_ = name; }
  6866. +
  6867. + const std::string& version() const { return version_; }
  6868. + void set_version(const std::string& version) {
  6869. + version_ = version;
  6870. + }
  6871. +
  6872. + const std::string& key() const { return key_; }
  6873. + void set_key(const std::string& key) {
  6874. + key_ = key;
  6875. + }
  6876. +
  6877. + const std::string& file_path() const { return file_path_; }
  6878. + void set_file_path(const std::string& file_path) {
  6879. + file_path_ = file_path;
  6880. + }
  6881. +
  6882. + const std::string& url_source() const { return url_source_; }
  6883. + void set_url_source(const std::string& url_source) {
  6884. + url_source_ = url_source;
  6885. + }
  6886. +
  6887. + const std::string& description() const { return description_; }
  6888. + void set_description(const std::string& description) {
  6889. + description_ = description;
  6890. + }
  6891. +
  6892. + const std::string& parser_error() const { return parser_error_; }
  6893. + void set_parser_error(const std::string& parser_error) {
  6894. + parser_error_ = parser_error;
  6895. + }
  6896. +
  6897. + bool force_disabled() const { return force_disabled_; }
  6898. + void set_force_disabled() {
  6899. + force_disabled_ = true;
  6900. + }
  6901. +
  6902. + // The place in the document to run the script.
  6903. + RunLocation run_location() const { return run_location_; }
  6904. + void set_run_location(RunLocation location) { run_location_ = location; }
  6905. +
  6906. + // Whether to emulate greasemonkey when running this script.
  6907. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6908. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6909. +
  6910. + // Whether to match all frames, or only the top one.
  6911. + bool match_all_frames() const { return match_all_frames_; }
  6912. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6913. +
  6914. + // Whether to match the origin as a fallback if the URL cannot be used
  6915. + // directly.
  6916. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6917. + return match_origin_as_fallback_;
  6918. + }
  6919. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6920. + match_origin_as_fallback_ = val;
  6921. + }
  6922. +
  6923. + // The globs, if any, that determine which pages this script runs against.
  6924. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6925. + const std::vector<std::string>& globs() const { return globs_; }
  6926. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6927. + void clear_globs() { globs_.clear(); }
  6928. + const std::vector<std::string>& exclude_globs() const {
  6929. + return exclude_globs_;
  6930. + }
  6931. + void add_exclude_glob(const std::string& glob) {
  6932. + exclude_globs_.push_back(glob);
  6933. + }
  6934. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6935. +
  6936. + // The URLPatterns, if any, that determine which pages this script runs
  6937. + // against.
  6938. + const URLPatternSet& url_patterns() const { return url_set_; }
  6939. + void add_url_pattern(const URLPattern& pattern);
  6940. + const URLPatternSet& exclude_url_patterns() const {
  6941. + return exclude_url_set_;
  6942. + }
  6943. + void add_exclude_url_pattern(const URLPattern& pattern);
  6944. +
  6945. + // List of js scripts for this user script
  6946. + FileList& js_scripts() { return js_scripts_; }
  6947. + const FileList& js_scripts() const { return js_scripts_; }
  6948. +
  6949. + // List of css scripts for this user script
  6950. + FileList& css_scripts() { return css_scripts_; }
  6951. + const FileList& css_scripts() const { return css_scripts_; }
  6952. +
  6953. + const std::string& extension_id() const { return host_id_.id(); }
  6954. +
  6955. + const HostID& host_id() const { return host_id_; }
  6956. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  6957. +
  6958. + const ConsumerInstanceType& consumer_instance_type() const {
  6959. + return consumer_instance_type_;
  6960. + }
  6961. + void set_consumer_instance_type(
  6962. + const ConsumerInstanceType& consumer_instance_type) {
  6963. + consumer_instance_type_ = consumer_instance_type;
  6964. + }
  6965. +
  6966. + int id() const { return user_script_id_; }
  6967. + void set_id(int id) { user_script_id_ = id; }
  6968. +
  6969. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  6970. + // belong here. We should be able to determine this in the renderer/ where it
  6971. + // is used.
  6972. + bool is_incognito_enabled() const { return incognito_enabled_; }
  6973. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  6974. +
  6975. + // Returns true if the script should be applied to the specified URL, false
  6976. + // otherwise.
  6977. + bool MatchesURL(const GURL& url) const;
  6978. +
  6979. + // Returns true if the script should be applied to the given
  6980. + // |effective_document_url|. It is the caller's responsibility to calculate
  6981. + // |effective_document_url| based on match_origin_as_fallback().
  6982. + bool MatchesDocument(const GURL& effective_document_url,
  6983. + bool is_subframe) const;
  6984. +
  6985. + // Serializes the UserScript into a pickle. The content of the scripts and
  6986. + // paths to UserScript::Files will not be serialized!
  6987. + void Pickle(base::Pickle* pickle) const;
  6988. +
  6989. + // Deserializes the script from a pickle. Note that this always succeeds
  6990. + // because presumably we were the one that pickled it, and we did it
  6991. + // correctly.
  6992. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6993. +
  6994. + private:
  6995. + // base::Pickle helper functions used to pickle the individual types of
  6996. + // components.
  6997. + void PickleGlobs(base::Pickle* pickle,
  6998. + const std::vector<std::string>& globs) const;
  6999. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  7000. + void PickleURLPatternSet(base::Pickle* pickle,
  7001. + const URLPatternSet& pattern_list) const;
  7002. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  7003. +
  7004. + // Unpickle helper functions used to unpickle individual types of components.
  7005. + void UnpickleGlobs(const base::Pickle& pickle,
  7006. + base::PickleIterator* iter,
  7007. + std::vector<std::string>* globs);
  7008. + void UnpickleHostID(const base::Pickle& pickle,
  7009. + base::PickleIterator* iter,
  7010. + HostID* host_id);
  7011. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  7012. + base::PickleIterator* iter,
  7013. + URLPatternSet* pattern_list);
  7014. + void UnpickleScripts(const base::Pickle& pickle,
  7015. + base::PickleIterator* iter,
  7016. + FileList* scripts);
  7017. +
  7018. + // The location to run the script inside the document.
  7019. + RunLocation run_location_ = DOCUMENT_IDLE;
  7020. +
  7021. + // The namespace of the script. This is used by Greasemonkey in the same way
  7022. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  7023. + std::string name_space_;
  7024. +
  7025. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  7026. + std::string name_;
  7027. +
  7028. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  7029. + std::string description_;
  7030. +
  7031. + // Parser error to show to user
  7032. + std::string parser_error_;
  7033. +
  7034. + // A version number of the script. Only used when parsing Greasemonkey-style
  7035. + // scripts.
  7036. + std::string version_;
  7037. +
  7038. + // Greasemonkey-style globs that determine pages to inject the script into.
  7039. + // These are only used with standalone scripts.
  7040. + std::vector<std::string> globs_;
  7041. + std::vector<std::string> exclude_globs_;
  7042. +
  7043. + // URLPatterns that determine pages to inject the script into. These are
  7044. + // only used with scripts that are part of extensions.
  7045. + URLPatternSet url_set_;
  7046. + URLPatternSet exclude_url_set_;
  7047. +
  7048. + // List of js scripts defined in content_scripts
  7049. + FileList js_scripts_;
  7050. +
  7051. + // List of css scripts defined in content_scripts
  7052. + FileList css_scripts_;
  7053. +
  7054. + // internal key of scripts
  7055. + std::string key_;
  7056. +
  7057. + std::string file_path_;
  7058. +
  7059. + // url source of script
  7060. + std::string url_source_;
  7061. +
  7062. + // The ID of the host this script is a part of. The |ID| of the
  7063. + // |host_id| can be empty if the script is a "standlone" user script.
  7064. + HostID host_id_;
  7065. +
  7066. + // The type of the consumer instance that the script will be injected.
  7067. + ConsumerInstanceType consumer_instance_type_ = TAB;
  7068. +
  7069. + // The globally-unique id associated with this user script. -1 indicates
  7070. + // "invalid".
  7071. + int user_script_id_ = -1;
  7072. +
  7073. + // Whether we should try to emulate Greasemonkey's APIs when running this
  7074. + // script.
  7075. + bool emulate_greasemonkey_ = false;
  7076. +
  7077. + // Whether the user script should run in all frames, or only just the top one.
  7078. + bool match_all_frames_ = false;
  7079. +
  7080. + // Whether the user script should run in frames whose initiator / precursor
  7081. + // origin matches a match pattern, if an appropriate URL cannot be found for
  7082. + // the frame for matching purposes, such as in the case of about:, data:, and
  7083. + // other schemes.
  7084. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  7085. + MatchOriginAsFallbackBehavior::kNever;
  7086. +
  7087. + // True if the script should be injected into an incognito tab.
  7088. + bool incognito_enabled_ = false;
  7089. +
  7090. + // Script cannot be enabled
  7091. + bool force_disabled_ = false;
  7092. +
  7093. + DISALLOW_COPY_AND_ASSIGN(UserScript);
  7094. +};
  7095. +
  7096. +// Information we need while removing scripts from a UserScriptLoader.
  7097. +struct UserScriptIDPair {
  7098. + UserScriptIDPair(int id, const HostID& host_id);
  7099. + explicit UserScriptIDPair(int id);
  7100. +
  7101. + int id;
  7102. + HostID host_id;
  7103. +};
  7104. +
  7105. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  7106. +
  7107. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  7108. +
  7109. +} // namespace extensions
  7110. +
  7111. +#endif // USERSCRIPTS_COMMON_USER_SCRIPT_H_
  7112. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  7113. new file mode 100644
  7114. --- /dev/null
  7115. +++ b/components/user_scripts/common/user_scripts_features.cc
  7116. @@ -0,0 +1,32 @@
  7117. +/*
  7118. + This file is part of Bromite.
  7119. +
  7120. + Bromite is free software: you can redistribute it and/or modify
  7121. + it under the terms of the GNU General Public License as published by
  7122. + the Free Software Foundation, either version 3 of the License, or
  7123. + (at your option) any later version.
  7124. +
  7125. + Bromite is distributed in the hope that it will be useful,
  7126. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7127. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7128. + GNU General Public License for more details.
  7129. +
  7130. + You should have received a copy of the GNU General Public License
  7131. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7132. +*/
  7133. +
  7134. +#include "user_scripts_features.h"
  7135. +
  7136. +#include "build/build_config.h"
  7137. +
  7138. +namespace user_scripts {
  7139. +
  7140. +namespace features {
  7141. +
  7142. +const base::Feature kEnableLoggingUserScripts =
  7143. + {"EnableLoggingUserScripts",
  7144. + base::FEATURE_DISABLED_BY_DEFAULT};
  7145. +
  7146. +}
  7147. +
  7148. +}
  7149. \ No newline at end of file
  7150. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  7151. new file mode 100644
  7152. --- /dev/null
  7153. +++ b/components/user_scripts/common/user_scripts_features.h
  7154. @@ -0,0 +1,34 @@
  7155. +/*
  7156. + This file is part of Bromite.
  7157. +
  7158. + Bromite is free software: you can redistribute it and/or modify
  7159. + it under the terms of the GNU General Public License as published by
  7160. + the Free Software Foundation, either version 3 of the License, or
  7161. + (at your option) any later version.
  7162. +
  7163. + Bromite is distributed in the hope that it will be useful,
  7164. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7165. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7166. + GNU General Public License for more details.
  7167. +
  7168. + You should have received a copy of the GNU General Public License
  7169. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7170. +*/
  7171. +
  7172. +#ifndef USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7173. +#define USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7174. +
  7175. +// This file defines all the base::FeatureList features for the Password Manager
  7176. +// module.
  7177. +
  7178. +#include "base/feature_list.h"
  7179. +
  7180. +namespace user_scripts {
  7181. +
  7182. +namespace features {
  7183. + extern const base::Feature kEnableLoggingUserScripts;
  7184. +}
  7185. +
  7186. +}
  7187. +
  7188. +#endif
  7189. \ No newline at end of file
  7190. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  7191. new file mode 100755
  7192. --- /dev/null
  7193. +++ b/components/user_scripts/common/view_type.cc
  7194. @@ -0,0 +1,39 @@
  7195. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7196. +// Use of this source code is governed by a BSD-style license that can be
  7197. +// found in the LICENSE file.
  7198. +
  7199. +#include "view_type.h"
  7200. +
  7201. +#include "base/strings/string_piece.h"
  7202. +
  7203. +namespace user_scripts {
  7204. +
  7205. +bool GetViewTypeFromString(const std::string& view_type,
  7206. + ViewType* view_type_out) {
  7207. + // TODO(devlin): This map doesn't contain the following values:
  7208. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  7209. + // - VIEW_TYPE_COMPONENT
  7210. + // - VIEW_TYPE_EXTENSION_GUEST
  7211. + // Why? Is it just because we don't expose those types to JS?
  7212. + static const struct {
  7213. + ViewType type;
  7214. + base::StringPiece name;
  7215. + } constexpr kTypeMap[] = {
  7216. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  7217. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  7218. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  7219. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  7220. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  7221. + };
  7222. +
  7223. + for (const auto& entry : kTypeMap) {
  7224. + if (entry.name == view_type) {
  7225. + *view_type_out = entry.type;
  7226. + return true;
  7227. + }
  7228. + }
  7229. +
  7230. + return false;
  7231. +}
  7232. +
  7233. +} // namespace extensions
  7234. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  7235. new file mode 100755
  7236. --- /dev/null
  7237. +++ b/components/user_scripts/common/view_type.h
  7238. @@ -0,0 +1,48 @@
  7239. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7240. +// Use of this source code is governed by a BSD-style license that can be
  7241. +// found in the LICENSE file.
  7242. +
  7243. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7244. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7245. +
  7246. +#include <string>
  7247. +
  7248. +namespace user_scripts {
  7249. +
  7250. +// Icky RTTI used by a few systems to distinguish the host type of a given
  7251. +// WebContents.
  7252. +//
  7253. +// Do not change or reuse the the entry values in this list as this is used in
  7254. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  7255. +//
  7256. +// TODO(aa): Remove this and teach those systems to keep track of their own
  7257. +// data.
  7258. +enum ViewType {
  7259. + VIEW_TYPE_INVALID = 0,
  7260. + // VIEW_TYPE_APP_WINDOW = 1,
  7261. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  7262. +
  7263. + // // For custom parts of Chrome if no other type applies.
  7264. + // VIEW_TYPE_COMPONENT = 3,
  7265. +
  7266. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  7267. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  7268. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  7269. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  7270. +
  7271. + // Panels were removed in https://crbug.com/571511.
  7272. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  7273. +
  7274. + VIEW_TYPE_TAB_CONTENTS = 9,
  7275. +
  7276. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  7277. +};
  7278. +
  7279. +// Matches the |view_type| to the corresponding ViewType, and populates
  7280. +// |view_type_out|. Returns true if a match is found.
  7281. +bool GetViewTypeFromString(const std::string& view_type,
  7282. + ViewType* view_type_out);
  7283. +
  7284. +} // namespace extensions
  7285. +
  7286. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7287. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  7288. new file mode 100755
  7289. --- /dev/null
  7290. +++ b/components/user_scripts/renderer/BUILD.gn
  7291. @@ -0,0 +1,67 @@
  7292. +# Copyright 2015 The Chromium Authors. All rights reserved.
  7293. +# Use of this source code is governed by a BSD-style license that can be
  7294. +# found in the LICENSE file.
  7295. +
  7296. +import("//tools/grit/grit_rule.gni")
  7297. +import("//tools/grit/repack.gni")
  7298. +
  7299. +group("user_scripts_resources") {
  7300. + public_deps = [
  7301. + ":user_scripts_renderer_resources",
  7302. + ]
  7303. +}
  7304. +
  7305. +grit("user_scripts_renderer_resources") {
  7306. + source = "resources/user_scripts_renderer_resources.grd"
  7307. + outputs = [
  7308. + "grit/user_scripts_renderer_resources.h",
  7309. + "user_scripts_renderer_resources.pak",
  7310. + ]
  7311. + grit_flags = [
  7312. + "-E",
  7313. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  7314. + ]
  7315. +}
  7316. +
  7317. +static_library("renderer") {
  7318. + sources = [
  7319. + "extension_frame_helper.cc",
  7320. + "extension_frame_helper.h",
  7321. + "injection_host.cc",
  7322. + "injection_host.h",
  7323. + "script_injection_manager.cc",
  7324. + "script_injection_manager.h",
  7325. + "script_injection_callback.cc",
  7326. + "script_injection_callback.h",
  7327. + "script_injection.cc",
  7328. + "script_injection.h",
  7329. + "script_injector.h",
  7330. + "script_context.cc",
  7331. + "script_context.h",
  7332. + "scripts_run_info.cc",
  7333. + "scripts_run_info.h",
  7334. + "user_script_injector.cc",
  7335. + "user_script_injector.h",
  7336. + "user_script_set_manager.cc",
  7337. + "user_script_set_manager.h",
  7338. + "user_script_set.cc",
  7339. + "user_script_set.h",
  7340. + "user_scripts_dispatcher.cc",
  7341. + "user_scripts_dispatcher.h",
  7342. + "user_scripts_renderer_client.cc",
  7343. + "user_scripts_renderer_client.h",
  7344. + "web_ui_injection_host.cc",
  7345. + "web_ui_injection_host.h",
  7346. + ]
  7347. +
  7348. + deps = [
  7349. + ":user_scripts_resources",
  7350. + "//base",
  7351. + "//content/public/common",
  7352. + "//content/public/renderer",
  7353. + "//components/user_scripts/common",
  7354. + "//mojo/public/cpp/bindings",
  7355. + "//third_party/blink/public:blink_headers",
  7356. + "//v8",
  7357. + ]
  7358. +}
  7359. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  7360. new file mode 100755
  7361. --- /dev/null
  7362. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  7363. @@ -0,0 +1,96 @@
  7364. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7365. +// Use of this source code is governed by a BSD-style license that can be
  7366. +// found in the LICENSE file.
  7367. +
  7368. +#include "extension_frame_helper.h"
  7369. +
  7370. +#include <set>
  7371. +
  7372. +#include "base/metrics/histogram_macros.h"
  7373. +#include "base/strings/string_util.h"
  7374. +#include "base/timer/elapsed_timer.h"
  7375. +#include "content/public/renderer/render_frame.h"
  7376. +#include "content/public/renderer/render_view.h"
  7377. +#include "../common/constants.h"
  7378. +#include "third_party/blink/public/platform/web_security_origin.h"
  7379. +#include "third_party/blink/public/web/web_console_message.h"
  7380. +#include "third_party/blink/public/web/web_document.h"
  7381. +#include "third_party/blink/public/web/web_document_loader.h"
  7382. +#include "third_party/blink/public/web/web_local_frame.h"
  7383. +#include "third_party/blink/public/web/web_settings.h"
  7384. +#include "third_party/blink/public/web/web_view.h"
  7385. +
  7386. +namespace user_scripts {
  7387. +
  7388. +namespace {
  7389. +
  7390. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  7391. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  7392. +
  7393. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  7394. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  7395. +void RunCallbacksWhileFrameIsValid(
  7396. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  7397. + std::vector<base::OnceClosure>* callbacks_to_be_run_and_cleared) {
  7398. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  7399. + // callbacks that are added during the iteration.
  7400. + std::vector<base::OnceClosure> callbacks;
  7401. + callbacks_to_be_run_and_cleared->swap(callbacks);
  7402. + for (auto& callback : callbacks) {
  7403. + std::move(callback).Run();
  7404. + if (!frame_helper.get())
  7405. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  7406. + }
  7407. +}
  7408. +
  7409. +} // namespace
  7410. +
  7411. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  7412. + : content::RenderFrameObserver(render_frame),
  7413. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  7414. + tab_id_(-1) {
  7415. + g_frame_helpers.Get().insert(this);
  7416. +}
  7417. +
  7418. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  7419. + g_frame_helpers.Get().erase(this);
  7420. +}
  7421. +
  7422. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  7423. + base::OnceClosure callback) {
  7424. + document_element_created_callbacks_.push_back(std::move(callback));
  7425. +}
  7426. +
  7427. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  7428. + base::OnceClosure callback) {
  7429. + document_load_finished_callbacks_.push_back(std::move(callback));
  7430. +}
  7431. +
  7432. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  7433. + base::OnceClosure callback) {
  7434. + document_idle_callbacks_.push_back(std::move(callback));
  7435. +}
  7436. +
  7437. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  7438. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7439. + &document_element_created_callbacks_);
  7440. + // |this| might be dead by now.
  7441. +}
  7442. +
  7443. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  7444. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7445. + &document_load_finished_callbacks_);
  7446. + // |this| might be dead by now.
  7447. +}
  7448. +
  7449. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  7450. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7451. + &document_idle_callbacks_);
  7452. + // |this| might be dead by now.
  7453. +}
  7454. +
  7455. +void ExtensionFrameHelper::OnDestruct() {
  7456. + delete this;
  7457. +}
  7458. +
  7459. +} // namespace user_scripts
  7460. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  7461. new file mode 100755
  7462. --- /dev/null
  7463. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  7464. @@ -0,0 +1,92 @@
  7465. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7466. +// Use of this source code is governed by a BSD-style license that can be
  7467. +// found in the LICENSE file.
  7468. +
  7469. +#ifndef USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7470. +#define USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7471. +
  7472. +#include <string>
  7473. +#include <vector>
  7474. +
  7475. +#include "base/callback_forward.h"
  7476. +#include "base/macros.h"
  7477. +#include "base/memory/weak_ptr.h"
  7478. +#include "content/public/renderer/render_frame_observer.h"
  7479. +#include "content/public/renderer/render_frame_observer_tracker.h"
  7480. +#include "../common/view_type.h"
  7481. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  7482. +#include "v8/include/v8.h"
  7483. +
  7484. +struct ExtensionMsg_ExternalConnectionInfo;
  7485. +struct ExtensionMsg_TabConnectionInfo;
  7486. +
  7487. +namespace base {
  7488. +class ListValue;
  7489. +}
  7490. +
  7491. +namespace user_scripts {
  7492. +
  7493. +class Dispatcher;
  7494. +struct Message;
  7495. +struct PortId;
  7496. +class ScriptContext;
  7497. +
  7498. +// RenderFrame-level plumbing for extension features.
  7499. +class ExtensionFrameHelper
  7500. + : public content::RenderFrameObserver,
  7501. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  7502. + public:
  7503. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  7504. + Dispatcher* extension_dispatcher*/);
  7505. + ~ExtensionFrameHelper() override;
  7506. +
  7507. + int tab_id() const { return tab_id_; }
  7508. +
  7509. + // Called when the document element has been inserted in this frame. This
  7510. + // method may invoke untrusted JavaScript code that invalidate the frame and
  7511. + // this ExtensionFrameHelper.
  7512. + void RunScriptsAtDocumentStart();
  7513. +
  7514. + // Called after the DOMContentLoaded event has fired.
  7515. + void RunScriptsAtDocumentEnd();
  7516. +
  7517. + // Called before the window.onload event is fired.
  7518. + void RunScriptsAtDocumentIdle();
  7519. +
  7520. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  7521. + // notification. Only call this when you are certain that there will be such a
  7522. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  7523. + // Otherwise the callback is never invoked, or invoked for a document that you
  7524. + // were not expecting.
  7525. + void ScheduleAtDocumentStart(base::OnceClosure callback);
  7526. +
  7527. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  7528. + void ScheduleAtDocumentEnd(base::OnceClosure callback);
  7529. +
  7530. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  7531. + void ScheduleAtDocumentIdle(base::OnceClosure callback);
  7532. +
  7533. + private:
  7534. +
  7535. + void OnDestruct() override;
  7536. +
  7537. + // The id of the tab the render frame is attached to.
  7538. + int tab_id_;
  7539. +
  7540. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  7541. + std::vector<base::OnceClosure> document_element_created_callbacks_;
  7542. +
  7543. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  7544. + std::vector<base::OnceClosure> document_load_finished_callbacks_;
  7545. +
  7546. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  7547. + std::vector<base::OnceClosure> document_idle_callbacks_;
  7548. +
  7549. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  7550. +
  7551. + DISALLOW_COPY_AND_ASSIGN(ExtensionFrameHelper);
  7552. +};
  7553. +
  7554. +} // namespace extensions
  7555. +
  7556. +#endif // USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7557. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  7558. new file mode 100755
  7559. --- /dev/null
  7560. +++ b/components/user_scripts/renderer/injection_host.cc
  7561. @@ -0,0 +1,12 @@
  7562. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7563. +// Use of this source code is governed by a BSD-style license that can be
  7564. +// found in the LICENSE file.
  7565. +
  7566. +#include "injection_host.h"
  7567. +
  7568. +InjectionHost::InjectionHost(const HostID& host_id) :
  7569. + id_(host_id) {
  7570. +}
  7571. +
  7572. +InjectionHost::~InjectionHost() {
  7573. +}
  7574. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  7575. new file mode 100755
  7576. --- /dev/null
  7577. +++ b/components/user_scripts/renderer/injection_host.h
  7578. @@ -0,0 +1,42 @@
  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. +#ifndef USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7584. +#define USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7585. +
  7586. +#include "base/macros.h"
  7587. +#include "../common/host_id.h"
  7588. +#include "url/gurl.h"
  7589. +
  7590. +namespace content {
  7591. +class RenderFrame;
  7592. +}
  7593. +
  7594. +// An interface for all kinds of hosts who own user scripts.
  7595. +class InjectionHost {
  7596. + public:
  7597. + InjectionHost(const HostID& host_id);
  7598. + virtual ~InjectionHost();
  7599. +
  7600. + // Returns the CSP to be used for the isolated world. Currently this only
  7601. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  7602. + // bypassed.
  7603. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  7604. +
  7605. + // The base url for the host.
  7606. + virtual const GURL& url() const = 0;
  7607. +
  7608. + // The human-readable name of the host.
  7609. + virtual const std::string& name() const = 0;
  7610. +
  7611. + const HostID& id() const { return id_; }
  7612. +
  7613. + private:
  7614. + // The ID of the host.
  7615. + HostID id_;
  7616. +
  7617. + DISALLOW_COPY_AND_ASSIGN(InjectionHost);
  7618. +};
  7619. +
  7620. +#endif // USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7621. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7622. new file mode 100755
  7623. --- /dev/null
  7624. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7625. @@ -0,0 +1,82 @@
  7626. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7627. +// Use of this source code is governed by a BSD-style license that can be
  7628. +// found in the LICENSE file.
  7629. +
  7630. +// -----------------------------------------------------------------------------
  7631. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  7632. +// have your change take effect.
  7633. +// -----------------------------------------------------------------------------
  7634. +
  7635. +// Partial implementation of the Greasemonkey API, see:
  7636. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  7637. +
  7638. +function GM_addStyle(css) {
  7639. + var parent = document.getElementsByTagName("head")[0];
  7640. + if (!parent) {
  7641. + parent = document.documentElement;
  7642. + }
  7643. + var style = document.createElement("style");
  7644. + style.type = "text/css";
  7645. + var textNode = document.createTextNode(css);
  7646. + style.appendChild(textNode);
  7647. + parent.appendChild(style);
  7648. +}
  7649. +
  7650. +function GM_xmlhttpRequest(details) {
  7651. + function setupEvent(xhr, url, eventName, callback) {
  7652. + xhr[eventName] = function () {
  7653. + var isComplete = xhr.readyState == 4;
  7654. + var responseState = {
  7655. + responseText: xhr.responseText,
  7656. + readyState: xhr.readyState,
  7657. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  7658. + status: isComplete ? xhr.status : 0,
  7659. + statusText: isComplete ? xhr.statusText : "",
  7660. + finalUrl: isComplete ? url : ""
  7661. + };
  7662. + callback(responseState);
  7663. + };
  7664. + }
  7665. +
  7666. + var xhr = new XMLHttpRequest();
  7667. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  7668. + for (var i = 0; i < eventNames.length; i++ ) {
  7669. + var eventName = eventNames[i];
  7670. + if (eventName in details) {
  7671. + setupEvent(xhr, details.url, eventName, details[eventName]);
  7672. + }
  7673. + }
  7674. +
  7675. + xhr.open(details.method, details.url);
  7676. +
  7677. + if (details.overrideMimeType) {
  7678. + xhr.overrideMimeType(details.overrideMimeType);
  7679. + }
  7680. + if (details.headers) {
  7681. + for (var header in details.headers) {
  7682. + xhr.setRequestHeader(header, details.headers[header]);
  7683. + }
  7684. + }
  7685. + xhr.send(details.data ? details.data : null);
  7686. +}
  7687. +
  7688. +function GM_openInTab(url) {
  7689. + window.open(url, "");
  7690. +}
  7691. +
  7692. +function GM_log(message) {
  7693. + window.console.log(message);
  7694. +}
  7695. +
  7696. +(function() {
  7697. + function generateGreasemonkeyStub(name) {
  7698. + return function() {
  7699. + console.log("%s is not supported.", name);
  7700. + };
  7701. + }
  7702. +
  7703. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  7704. + for (var i = 0, api; api = apis[i]; i++) {
  7705. + window[api] = generateGreasemonkeyStub(api);
  7706. + }
  7707. +})();
  7708. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7709. new file mode 100755
  7710. --- /dev/null
  7711. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7712. @@ -0,0 +1,14 @@
  7713. +<?xml version="1.0" encoding="UTF-8"?>
  7714. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  7715. + <outputs>
  7716. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  7717. + <emit emit_type='prepend'></emit>
  7718. + </output>
  7719. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  7720. + </outputs>
  7721. + <release seq="1">
  7722. + <includes>
  7723. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  7724. + </includes>
  7725. + </release>
  7726. +</grit>
  7727. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  7728. new file mode 100755
  7729. --- /dev/null
  7730. +++ b/components/user_scripts/renderer/script_context.cc
  7731. @@ -0,0 +1,215 @@
  7732. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7733. +// Use of this source code is governed by a BSD-style license that can be
  7734. +// found in the LICENSE file.
  7735. +
  7736. +#include "script_context.h"
  7737. +
  7738. +#include "base/command_line.h"
  7739. +#include "base/containers/flat_set.h"
  7740. +#include "base/containers/contains.h"
  7741. +#include "base/logging.h"
  7742. +#include "base/no_destructor.h"
  7743. +#include "base/stl_util.h"
  7744. +#include "base/strings/string_util.h"
  7745. +#include "base/strings/stringprintf.h"
  7746. +#include "base/values.h"
  7747. +#include "content/public/common/content_switches.h"
  7748. +#include "content/public/common/url_constants.h"
  7749. +#include "content/public/renderer/render_frame.h"
  7750. +#include "../common/constants.h"
  7751. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  7752. +#include "third_party/blink/public/platform/web_security_origin.h"
  7753. +#include "third_party/blink/public/web/web_document.h"
  7754. +#include "third_party/blink/public/web/web_document_loader.h"
  7755. +#include "third_party/blink/public/web/web_local_frame.h"
  7756. +#include "third_party/blink/public/web/web_navigation_params.h"
  7757. +#include "v8/include/v8.h"
  7758. +
  7759. +namespace user_scripts {
  7760. +
  7761. +namespace {
  7762. +
  7763. +GURL GetEffectiveDocumentURL(
  7764. + blink::WebLocalFrame* frame,
  7765. + const GURL& document_url,
  7766. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  7767. + bool allow_inaccessible_parents) {
  7768. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  7769. + switch (match_origin_as_fallback) {
  7770. + case MatchOriginAsFallbackBehavior::kNever:
  7771. + return false;
  7772. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  7773. + return document_url.SchemeIs(url::kAboutScheme);
  7774. + case MatchOriginAsFallbackBehavior::kAlways:
  7775. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  7776. + return document_url.SchemeIs(url::kAboutScheme) ||
  7777. + document_url.SchemeIs(url::kDataScheme);
  7778. + }
  7779. +
  7780. + NOTREACHED();
  7781. + };
  7782. +
  7783. + // If we don't need to consider the origin, we're done.
  7784. + if (!should_consider_origin())
  7785. + return document_url;
  7786. +
  7787. + // Get the "security origin" for the frame. For about: frames, this is the
  7788. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7789. + // https://example.com will have the security origin of https://example.com.
  7790. + // Other frames, like data: frames, will have an opaque origin. For these,
  7791. + // we can get the precursor origin.
  7792. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7793. + const url::Origin frame_origin = web_frame_origin;
  7794. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7795. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7796. +
  7797. + // When there's no valid tuple (which can happen in the case of e.g. a
  7798. + // browser-initiated navigation to an opaque URL), there's no origin to
  7799. + // fallback to. Bail.
  7800. + if (!tuple_or_precursor_tuple.IsValid())
  7801. + return document_url;
  7802. +
  7803. + const url::Origin origin_or_precursor_origin =
  7804. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7805. +
  7806. + if (!allow_inaccessible_parents &&
  7807. + !web_frame_origin.CanAccess(
  7808. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7809. + // The frame can't access its precursor. Bail.
  7810. + return document_url;
  7811. + }
  7812. +
  7813. + // Looks like the initiator origin is an appropriate fallback!
  7814. +
  7815. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7816. + // The easy case! We use the origin directly. We're done.
  7817. + return origin_or_precursor_origin.GetURL();
  7818. + }
  7819. +
  7820. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7821. + match_origin_as_fallback);
  7822. +
  7823. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7824. + // match patterns that are associated with paths as well, not just origins.
  7825. + // For instance, if an extension wants to run on google.com/maps/* with
  7826. + // match_about_blank true, then it should run on about:-scheme frames created
  7827. + // by google.com/maps, but not about:-scheme frames created by google.com
  7828. + // (which is what the precursor tuple origin would be).
  7829. +
  7830. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7831. + // with the same origin as the precursor and return its URL.
  7832. + // Note: This can return the incorrect result, e.g. if a parent frame
  7833. + // navigates a grandchild frame.
  7834. + blink::WebFrame* parent = frame;
  7835. + GURL parent_url;
  7836. + blink::WebDocument parent_document;
  7837. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7838. + do {
  7839. + already_visited_frames.insert(parent);
  7840. + if (parent->Parent())
  7841. + parent = parent->Parent();
  7842. + else
  7843. + parent = parent->Opener();
  7844. +
  7845. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7846. + // https://crbug.com/883526.
  7847. + if (base::Contains(already_visited_frames, parent))
  7848. + return document_url;
  7849. +
  7850. + parent_document = parent && parent->IsWebLocalFrame()
  7851. + ? parent->ToWebLocalFrame()->GetDocument()
  7852. + : blink::WebDocument();
  7853. +
  7854. + // We reached the end of the ancestral chain without finding a valid parent,
  7855. + // or found a remote web frame (in which case, it's a different origin).
  7856. + // Bail and use the original URL.
  7857. + if (parent_document.IsNull())
  7858. + return document_url;
  7859. +
  7860. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7861. + url::Origin(parent->GetSecurityOrigin())
  7862. + .GetTupleOrPrecursorTupleIfOpaque();
  7863. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7864. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7865. + // The parent has a different tuple origin than frame; this could happen
  7866. + // in edge cases where a parent navigates an iframe or popup of a child
  7867. + // frame at a different origin. [1] In this case, bail, since we can't
  7868. + // find a full URL (i.e., one including the path) with the same security
  7869. + // origin to use for the frame in question.
  7870. + // [1] Consider a frame tree like:
  7871. + // <html> <!--example.com-->
  7872. + // <iframe id="a" src="a.com">
  7873. + // <iframe id="b" src="b.com"></iframe>
  7874. + // </iframe>
  7875. + // </html>
  7876. + // Frame "a" is cross-origin from the top-level frame, and so the
  7877. + // example.com top-level frame can't directly access frame "b". However,
  7878. + // it can navigate it through
  7879. + // window.frames[0].frames[0].location.href = 'about:blank';
  7880. + // In that case, the precursor origin tuple origin of frame "b" would be
  7881. + // example.com, but the parent tuple origin is a.com.
  7882. + // Note that usually, this would have bailed earlier with a remote frame,
  7883. + // but it may not if we're at the process limit.
  7884. + return document_url;
  7885. + }
  7886. +
  7887. + parent_url = GURL(parent_document.Url());
  7888. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7889. +
  7890. + DCHECK(!parent_url.is_empty());
  7891. + DCHECK(!parent_document.IsNull());
  7892. +
  7893. + // We should know that the frame can access the parent document (unless we
  7894. + // explicitly allow it not to), since it has the same tuple origin as the
  7895. + // frame, and we checked the frame access above.
  7896. + DCHECK(allow_inaccessible_parents ||
  7897. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7898. + return parent_url;
  7899. +}
  7900. +
  7901. +using FrameToDocumentLoader =
  7902. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7903. +
  7904. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7905. + static base::NoDestructor<FrameToDocumentLoader> map;
  7906. + return *map;
  7907. +}
  7908. +
  7909. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7910. + const blink::WebLocalFrame* frame) {
  7911. + auto& map = FrameDocumentLoaderMap();
  7912. + auto it = map.find(frame);
  7913. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7914. +}
  7915. +
  7916. +} // namespace
  7917. +
  7918. +// static
  7919. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7920. + const blink::WebLocalFrame* frame) {
  7921. + // Normally we would use frame->document().url() to determine the document's
  7922. + // URL, but to decide whether to inject a content script, we use the URL from
  7923. + // the data source. This "quirk" helps prevents content scripts from
  7924. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7925. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7926. + // changes to match the parent document after Gmail document.writes into
  7927. + // it to create the editor.
  7928. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7929. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7930. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7931. +}
  7932. +
  7933. +// static
  7934. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7935. + blink::WebLocalFrame* frame,
  7936. + const GURL& document_url,
  7937. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7938. + // We explicitly allow inaccessible parents here. Extensions should still be
  7939. + // able to inject into a sandboxed iframe if it has access to the embedding
  7940. + // origin.
  7941. + constexpr bool allow_inaccessible_parents = true;
  7942. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7943. + allow_inaccessible_parents);
  7944. +}
  7945. +
  7946. +} // namespace extensions
  7947. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7948. new file mode 100755
  7949. --- /dev/null
  7950. +++ b/components/user_scripts/renderer/script_context.h
  7951. @@ -0,0 +1,70 @@
  7952. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7953. +// Use of this source code is governed by a BSD-style license that can be
  7954. +// found in the LICENSE file.
  7955. +
  7956. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7957. +#define USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7958. +
  7959. +#include <memory>
  7960. +#include <string>
  7961. +#include <utility>
  7962. +#include <vector>
  7963. +
  7964. +#include "base/callback.h"
  7965. +#include "base/compiler_specific.h"
  7966. +#include "base/macros.h"
  7967. +#include "base/threading/thread_checker.h"
  7968. +#include "base/unguessable_token.h"
  7969. +#include "../common/script_constants.h"
  7970. +#include "script_injection_callback.h"
  7971. +#include "url/gurl.h"
  7972. +#include "v8/include/v8.h"
  7973. +
  7974. +namespace blink {
  7975. +class WebDocumentLoader;
  7976. +class WebLocalFrame;
  7977. +}
  7978. +
  7979. +namespace content {
  7980. +class RenderFrame;
  7981. +}
  7982. +
  7983. +namespace user_scripts {
  7984. +
  7985. +// Extensions wrapper for a v8::Context.
  7986. +//
  7987. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  7988. +// destroyed that thread.
  7989. +//
  7990. +// Note that ScriptContexts bound to worker threads will not have the full
  7991. +// functionality as those bound to the main RenderThread.
  7992. +class ScriptContext {
  7993. + public:
  7994. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  7995. + // vaguely ScriptContext related, there's enough here that they probably
  7996. + // warrant another class or utility file.
  7997. +
  7998. + // Utility to get the URL we will match against for a frame. If the frame has
  7999. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  8000. + // The returned URL may be invalid.
  8001. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  8002. +
  8003. + // Used to determine the "effective" URL for extension script injection.
  8004. + // If |document_url| is an about: or data: URL, returns the URL of the first
  8005. + // frame without an about: or data: URL that matches the initiator origin.
  8006. + // This may not be the immediate parent. Returns |document_url| if it is not
  8007. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  8008. + // or if a suitable parent cannot be found.
  8009. + // Considers parent contexts that cannot be accessed (as is the case for
  8010. + // sandboxed frames).
  8011. + static GURL GetEffectiveDocumentURLForInjection(
  8012. + blink::WebLocalFrame* frame,
  8013. + const GURL& document_url,
  8014. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  8015. +
  8016. +// DISALLOW_COPY_AND_ASSIGN(ScriptContext);
  8017. +};
  8018. +
  8019. +} // namespace extensions
  8020. +
  8021. +#endif // USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  8022. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  8023. new file mode 100755
  8024. --- /dev/null
  8025. +++ b/components/user_scripts/renderer/script_injection.cc
  8026. @@ -0,0 +1,343 @@
  8027. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8028. +// Use of this source code is governed by a BSD-style license that can be
  8029. +// found in the LICENSE file.
  8030. +
  8031. +#include "script_injection.h"
  8032. +
  8033. +#include <map>
  8034. +#include <utility>
  8035. +
  8036. +#include "base/bind.h"
  8037. +#include "base/feature_list.h"
  8038. +#include "base/lazy_instance.h"
  8039. +#include "base/macros.h"
  8040. +#include "base/metrics/histogram_macros.h"
  8041. +#include "base/timer/elapsed_timer.h"
  8042. +#include "base/values.h"
  8043. +#include "base/logging.h"
  8044. +#include "content/public/renderer/render_frame.h"
  8045. +#include "content/public/renderer/render_frame_observer.h"
  8046. +#include "content/public/renderer/v8_value_converter.h"
  8047. +#include "../common/host_id.h"
  8048. +#include "script_injection_callback.h"
  8049. +#include "scripts_run_info.h"
  8050. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  8051. +#include "third_party/blink/public/platform/web_security_origin.h"
  8052. +#include "third_party/blink/public/platform/web_string.h"
  8053. +#include "third_party/blink/public/web/web_document.h"
  8054. +#include "third_party/blink/public/web/web_local_frame.h"
  8055. +#include "third_party/blink/public/web/web_script_source.h"
  8056. +#include "url/gurl.h"
  8057. +
  8058. +namespace user_scripts {
  8059. +
  8060. +namespace {
  8061. +
  8062. +using IsolatedWorldMap = std::map<std::string, int>;
  8063. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  8064. + LAZY_INSTANCE_INITIALIZER;
  8065. +
  8066. +const int64_t kInvalidRequestId = -1;
  8067. +
  8068. +// Gets the isolated world ID to use for the given |injection_host|. If no
  8069. +// isolated world has been created for that |injection_host| one will be created
  8070. +// and initialized.
  8071. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  8072. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  8073. +
  8074. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8075. +
  8076. + int id = 0;
  8077. + const std::string& key = injection_host->id().id();
  8078. + auto iter = isolated_worlds.find(key);
  8079. + if (iter != isolated_worlds.end()) {
  8080. + id = iter->second;
  8081. + } else {
  8082. + id = g_next_isolated_world_id++;
  8083. + // This map will tend to pile up over time, but realistically, you're never
  8084. + // going to have enough injection hosts for it to matter.
  8085. + isolated_worlds[key] = id;
  8086. + }
  8087. +
  8088. + blink::WebIsolatedWorldInfo info;
  8089. + info.security_origin =
  8090. + blink::WebSecurityOrigin::Create(injection_host->url());
  8091. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  8092. + info.stable_id = blink::WebString::FromUTF8(key);
  8093. +
  8094. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  8095. + if (csp)
  8096. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  8097. +
  8098. + // Even though there may be an existing world for this |injection_host|'s key,
  8099. + // the properties may have changed (e.g. due to an extension update).
  8100. + // Overwrite any existing entries.
  8101. + blink::SetIsolatedWorldInfo(id, info);
  8102. +
  8103. + return id;
  8104. +}
  8105. +
  8106. +// This class manages its own lifetime.
  8107. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  8108. + public:
  8109. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  8110. + : ScriptInjectionCallback(
  8111. + base::BindOnce(&TimedScriptInjectionCallback::OnCompleted,
  8112. + base::Unretained(this))),
  8113. + injection_(injection) {}
  8114. + ~TimedScriptInjectionCallback() override {}
  8115. +
  8116. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  8117. + if (injection_) {
  8118. + base::TimeTicks timestamp(base::TimeTicks::Now());
  8119. + absl::optional<base::TimeDelta> elapsed;
  8120. + // If the script will never execute (such as if the context is destroyed),
  8121. + // willExecute() will not be called, but OnCompleted() will. Only log a
  8122. + // time for execution if the script, in fact, executed.
  8123. + if (!start_time_.is_null())
  8124. + elapsed = timestamp - start_time_;
  8125. + injection_->OnJsInjectionCompleted(result, elapsed);
  8126. + }
  8127. + }
  8128. +
  8129. + void WillExecute() override {
  8130. + start_time_ = base::TimeTicks::Now();
  8131. + }
  8132. +
  8133. + private:
  8134. + base::WeakPtr<ScriptInjection> injection_;
  8135. + base::TimeTicks start_time_;
  8136. +};
  8137. +
  8138. +} // namespace
  8139. +
  8140. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  8141. +// false.
  8142. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  8143. + public:
  8144. + FrameWatcher(content::RenderFrame* render_frame,
  8145. + ScriptInjection* injection)
  8146. + : content::RenderFrameObserver(render_frame),
  8147. + injection_(injection) {}
  8148. + ~FrameWatcher() override {}
  8149. +
  8150. + private:
  8151. + void WillDetach() override { injection_->invalidate_render_frame(); }
  8152. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  8153. +
  8154. + ScriptInjection* injection_;
  8155. +
  8156. + DISALLOW_COPY_AND_ASSIGN(FrameWatcher);
  8157. +};
  8158. +
  8159. +// static
  8160. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  8161. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8162. +
  8163. + for (const auto& iter : isolated_worlds) {
  8164. + if (iter.second == isolated_world_id)
  8165. + return iter.first;
  8166. + }
  8167. + return std::string();
  8168. +}
  8169. +
  8170. +// static
  8171. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  8172. + g_isolated_worlds.Get().erase(host_id);
  8173. +}
  8174. +
  8175. +ScriptInjection::ScriptInjection(
  8176. + std::unique_ptr<ScriptInjector> injector,
  8177. + content::RenderFrame* render_frame,
  8178. + std::unique_ptr<const InjectionHost> injection_host,
  8179. + UserScript::RunLocation run_location,
  8180. + bool log_activity)
  8181. + : injector_(std::move(injector)),
  8182. + render_frame_(render_frame),
  8183. + injection_host_(std::move(injection_host)),
  8184. + run_location_(run_location),
  8185. + request_id_(kInvalidRequestId),
  8186. + complete_(false),
  8187. + did_inject_js_(false),
  8188. + log_activity_(log_activity),
  8189. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  8190. + CHECK(injection_host_.get());
  8191. +}
  8192. +
  8193. +ScriptInjection::~ScriptInjection() {
  8194. + if (!complete_)
  8195. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  8196. +}
  8197. +
  8198. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  8199. + UserScript::RunLocation current_location,
  8200. + ScriptsRunInfo* scripts_run_info,
  8201. + CompletionCallback async_completion_callback) {
  8202. + if (current_location < run_location_)
  8203. + return INJECTION_WAITING; // Wait for the right location.
  8204. +
  8205. + if (request_id_ != kInvalidRequestId) {
  8206. + // We're waiting for permission right now, try again later.
  8207. + return INJECTION_WAITING;
  8208. + }
  8209. +
  8210. + if (!injection_host_) {
  8211. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8212. + return INJECTION_FINISHED; // We're done.
  8213. + }
  8214. +
  8215. + InjectionResult result = Inject(scripts_run_info);
  8216. + // If the injection is blocked, we need to set the manager so we can
  8217. + // notify it upon completion.
  8218. + if (result == INJECTION_BLOCKED)
  8219. + async_completion_callback_ = std::move(async_completion_callback);
  8220. + return result;
  8221. +}
  8222. +
  8223. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  8224. + ScriptsRunInfo* scripts_run_info) {
  8225. + if (!injection_host_) {
  8226. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8227. + return INJECTION_FINISHED;
  8228. + }
  8229. +
  8230. + return Inject(scripts_run_info);
  8231. +}
  8232. +
  8233. +void ScriptInjection::OnHostRemoved() {
  8234. + injection_host_.reset(nullptr);
  8235. +}
  8236. +
  8237. +void ScriptInjection::NotifyWillNotInject(
  8238. + ScriptInjector::InjectFailureReason reason) {
  8239. + complete_ = true;
  8240. + injector_->OnWillNotInject(reason, render_frame_);
  8241. +}
  8242. +
  8243. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  8244. + ScriptsRunInfo* scripts_run_info) {
  8245. + DCHECK(injection_host_);
  8246. + //DCHECK(scripts_run_info);
  8247. + DCHECK(!complete_);
  8248. + bool should_inject_js = injector_->ShouldInjectJs(
  8249. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  8250. + bool should_inject_css = injector_->ShouldInjectCss(
  8251. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  8252. +
  8253. + // This can happen if the extension specified a script to
  8254. + // be run in multiple rules, and the script has already run.
  8255. + // See crbug.com/631247.
  8256. + if (!should_inject_js && !should_inject_css) {
  8257. + return INJECTION_FINISHED;
  8258. + }
  8259. +
  8260. + if (should_inject_js)
  8261. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  8262. + &(scripts_run_info->num_js));
  8263. + if (should_inject_css)
  8264. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  8265. + &(scripts_run_info->num_css));
  8266. +
  8267. + complete_ = did_inject_js_ || !should_inject_js;
  8268. +
  8269. + if (complete_) {
  8270. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8271. + render_frame_);
  8272. + } else {
  8273. + ++scripts_run_info->num_blocking_js;
  8274. + }
  8275. +
  8276. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  8277. +}
  8278. +
  8279. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  8280. + size_t* num_injected_js_scripts) {
  8281. + DCHECK(!did_inject_js_);
  8282. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  8283. + run_location_, executing_scripts, num_injected_js_scripts);
  8284. + DCHECK(!sources.empty());
  8285. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  8286. + bool is_user_gesture = injector_->IsUserGesture();
  8287. +
  8288. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  8289. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  8290. +
  8291. + base::ElapsedTimer exec_timer;
  8292. +
  8293. + // For content scripts executing during page load, we run them asynchronously
  8294. + // in order to reduce UI jank experienced by the user. (We don't do this for
  8295. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  8296. + // run, so we run them as soon as we can.)
  8297. + // Note: We could potentially also run deferred and browser-driven scripts
  8298. + // asynchronously; however, these are rare enough that there probably isn't
  8299. + // UI jank. If this changes, we can update this.
  8300. + bool should_execute_asynchronously =
  8301. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  8302. + (run_location_ == UserScript::DOCUMENT_END ||
  8303. + run_location_ == UserScript::DOCUMENT_IDLE);
  8304. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  8305. + should_execute_asynchronously
  8306. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  8307. + : blink::WebLocalFrame::kSynchronous;
  8308. +
  8309. + render_frame_->GetWebFrame()->RequestExecuteScript(
  8310. + world_id, sources, is_user_gesture,
  8311. + execution_option, callback.release(),
  8312. + blink::BackForwardCacheAware::kPossiblyDisallow);
  8313. +}
  8314. +
  8315. +void ScriptInjection::OnJsInjectionCompleted(
  8316. + const std::vector<v8::Local<v8::Value>>& results,
  8317. + absl::optional<base::TimeDelta> elapsed) {
  8318. + DCHECK(!did_inject_js_);
  8319. +
  8320. + bool expects_results = injector_->ExpectsResults();
  8321. + if (expects_results) {
  8322. + if (!results.empty() && !results[0].IsEmpty()) {
  8323. + // Right now, we only support returning single results (per frame).
  8324. + // It's safe to always use the main world context when converting
  8325. + // here. V8ValueConverterImpl shouldn't actually care about the
  8326. + // context scope, and it switches to v8::Object's creation context
  8327. + // when encountered.
  8328. + v8::Local<v8::Context> context =
  8329. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  8330. + execution_result_ =
  8331. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  8332. + }
  8333. + if (!execution_result_.get())
  8334. + execution_result_ = std::make_unique<base::Value>();
  8335. + }
  8336. + did_inject_js_ = true;
  8337. +
  8338. + // If |async_completion_callback_| is set, it means the script finished
  8339. + // asynchronously, and we should run it.
  8340. + if (!async_completion_callback_.is_null()) {
  8341. + complete_ = true;
  8342. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8343. + render_frame_);
  8344. + // Warning: this object can be destroyed after this line!
  8345. + std::move(async_completion_callback_).Run(this);
  8346. + }
  8347. +}
  8348. +
  8349. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  8350. + size_t* num_injected_stylesheets) {
  8351. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  8352. + run_location_, injected_stylesheets, num_injected_stylesheets);
  8353. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  8354. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  8355. + absl::optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  8356. + blink::WebDocument::CSSOrigin blink_css_origin =
  8357. + css_origin && *css_origin == CSS_ORIGIN_USER
  8358. + ? blink::WebDocument::kUserOrigin
  8359. + : blink::WebDocument::kAuthorOrigin;
  8360. + blink::WebStyleSheetKey style_sheet_key;
  8361. + if (const absl::optional<std::string>& injection_key =
  8362. + injector_->GetInjectionKey())
  8363. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  8364. + for (const blink::WebString& css : css_sources)
  8365. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  8366. + blink_css_origin);
  8367. +}
  8368. +
  8369. +} // namespace extensions
  8370. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  8371. new file mode 100755
  8372. --- /dev/null
  8373. +++ b/components/user_scripts/renderer/script_injection.h
  8374. @@ -0,0 +1,155 @@
  8375. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8376. +// Use of this source code is governed by a BSD-style license that can be
  8377. +// found in the LICENSE file.
  8378. +
  8379. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8380. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8381. +
  8382. +#include <stdint.h>
  8383. +
  8384. +#include <memory>
  8385. +#include <vector>
  8386. +
  8387. +#include "base/callback.h"
  8388. +#include "base/macros.h"
  8389. +#include "base/memory/weak_ptr.h"
  8390. +#include "../common/user_script.h"
  8391. +#include "injection_host.h"
  8392. +#include "script_injector.h"
  8393. +
  8394. +struct HostID;
  8395. +
  8396. +namespace content {
  8397. +class RenderFrame;
  8398. +}
  8399. +
  8400. +namespace v8 {
  8401. +class Value;
  8402. +template <class T> class Local;
  8403. +}
  8404. +
  8405. +namespace user_scripts {
  8406. +struct ScriptsRunInfo;
  8407. +
  8408. +// A script wrapper which is aware of whether or not it is allowed to execute,
  8409. +// and contains the implementation to do so.
  8410. +class ScriptInjection {
  8411. + public:
  8412. + enum InjectionResult {
  8413. + INJECTION_FINISHED,
  8414. + INJECTION_BLOCKED,
  8415. + INJECTION_WAITING
  8416. + };
  8417. +
  8418. + using CompletionCallback = base::OnceCallback<void(ScriptInjection*)>;
  8419. +
  8420. + // Return the id of the injection host associated with the given world.
  8421. + static std::string GetHostIdForIsolatedWorld(int world_id);
  8422. +
  8423. + // Remove the isolated world associated with the given injection host.
  8424. + static void RemoveIsolatedWorld(const std::string& host_id);
  8425. +
  8426. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  8427. + content::RenderFrame* render_frame,
  8428. + std::unique_ptr<const InjectionHost> injection_host,
  8429. + UserScript::RunLocation run_location,
  8430. + bool log_activity);
  8431. + ~ScriptInjection();
  8432. +
  8433. + // Try to inject the script at the |current_location|. This returns
  8434. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  8435. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  8436. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  8437. + // for permission purposes or because |current_location| is not the designated
  8438. + // |run_location_|).
  8439. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  8440. + // called upon completion.
  8441. + InjectionResult TryToInject(
  8442. + UserScript::RunLocation current_location,
  8443. + ScriptsRunInfo* scripts_run_info,
  8444. + CompletionCallback async_completion_callback);
  8445. +
  8446. + // Called when permission for the given injection has been granted.
  8447. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  8448. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  8449. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  8450. +
  8451. + // Resets the pointer of the injection host when the host is gone.
  8452. + void OnHostRemoved();
  8453. +
  8454. + void invalidate_render_frame() { render_frame_ = nullptr; }
  8455. +
  8456. + // Accessors.
  8457. + content::RenderFrame* render_frame() const { return render_frame_; }
  8458. + const HostID& host_id() const { return injection_host_->id(); }
  8459. + int64_t request_id() const { return request_id_; }
  8460. +
  8461. + // Called when JS injection for the given frame has been completed or
  8462. + // cancelled.
  8463. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  8464. + absl::optional<base::TimeDelta> elapsed);
  8465. +
  8466. + private:
  8467. + class FrameWatcher;
  8468. +
  8469. + // Sends a message to the browser to request permission to inject.
  8470. + void RequestPermissionFromBrowser();
  8471. +
  8472. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  8473. + // otherwise INJECTION_BLOCKED.
  8474. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  8475. +
  8476. + // Inject any JS scripts into the frame for the injection.
  8477. + void InjectJs(std::set<std::string>* executing_scripts,
  8478. + size_t* num_injected_js_scripts);
  8479. +
  8480. + // Inject any CSS source into the frame for the injection.
  8481. + void InjectCss(std::set<std::string>* injected_stylesheets,
  8482. + size_t* num_injected_stylesheets);
  8483. +
  8484. + // Notify that we will not inject, and mark it as acknowledged.
  8485. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  8486. +
  8487. + // The injector for this injection.
  8488. + std::unique_ptr<ScriptInjector> injector_;
  8489. +
  8490. + // The RenderFrame into which this should inject the script.
  8491. + content::RenderFrame* render_frame_;
  8492. +
  8493. + // The associated injection host.
  8494. + std::unique_ptr<const InjectionHost> injection_host_;
  8495. +
  8496. + // The location in the document load at which we inject the script.
  8497. + UserScript::RunLocation run_location_;
  8498. +
  8499. + // This injection's request id. This will be -1 unless the injection is
  8500. + // currently waiting on permission.
  8501. + int64_t request_id_;
  8502. +
  8503. + // Whether or not the injection is complete, either via injecting the script
  8504. + // or because it will never complete.
  8505. + bool complete_;
  8506. +
  8507. + // Whether or not the injection successfully injected JS.
  8508. + bool did_inject_js_;
  8509. +
  8510. + // Whether or not we should log dom activity for this injection.
  8511. + bool log_activity_;
  8512. +
  8513. + // Results storage.
  8514. + std::unique_ptr<base::Value> execution_result_;
  8515. +
  8516. + // The callback to run upon completing asynchronously.
  8517. + CompletionCallback async_completion_callback_;
  8518. +
  8519. + // A helper class to hold the render frame and watch for its deletion.
  8520. + std::unique_ptr<FrameWatcher> frame_watcher_;
  8521. +
  8522. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  8523. +
  8524. + DISALLOW_COPY_AND_ASSIGN(ScriptInjection);
  8525. +};
  8526. +
  8527. +} // namespace extensions
  8528. +
  8529. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8530. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  8531. new file mode 100755
  8532. --- /dev/null
  8533. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  8534. @@ -0,0 +1,25 @@
  8535. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8536. +// Use of this source code is governed by a BSD-style license that can be
  8537. +// found in the LICENSE file.
  8538. +
  8539. +#include "script_injection_callback.h"
  8540. +
  8541. +#include "third_party/blink/public/platform/web_vector.h"
  8542. +
  8543. +namespace user_scripts {
  8544. +
  8545. +ScriptInjectionCallback::ScriptInjectionCallback(
  8546. + CompleteCallback injection_completed_callback)
  8547. + : injection_completed_callback_(std::move(injection_completed_callback)) {}
  8548. +
  8549. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  8550. +}
  8551. +
  8552. +void ScriptInjectionCallback::Completed(
  8553. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  8554. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  8555. + std::move(injection_completed_callback_).Run(stl_result);
  8556. + delete this;
  8557. +}
  8558. +
  8559. +} // namespace extensions
  8560. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  8561. new file mode 100755
  8562. --- /dev/null
  8563. +++ b/components/user_scripts/renderer/script_injection_callback.h
  8564. @@ -0,0 +1,39 @@
  8565. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8566. +// Use of this source code is governed by a BSD-style license that can be
  8567. +// found in the LICENSE file.
  8568. +
  8569. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8570. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8571. +
  8572. +#include <vector>
  8573. +
  8574. +#include "base/callback.h"
  8575. +#include "base/macros.h"
  8576. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  8577. +#include "v8/include/v8.h"
  8578. +
  8579. +namespace user_scripts {
  8580. +
  8581. +// A wrapper around a callback to notify a script injection when injection
  8582. +// completes.
  8583. +// This class manages its own lifetime.
  8584. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  8585. + public:
  8586. + using CompleteCallback =
  8587. + base::OnceCallback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  8588. +
  8589. + explicit ScriptInjectionCallback(
  8590. + CompleteCallback injection_completed_callback);
  8591. + ~ScriptInjectionCallback() override;
  8592. +
  8593. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  8594. +
  8595. + private:
  8596. + CompleteCallback injection_completed_callback_;
  8597. +
  8598. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionCallback);
  8599. +};
  8600. +
  8601. +} // namespace extensions
  8602. +
  8603. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8604. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  8605. new file mode 100755
  8606. --- /dev/null
  8607. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  8608. @@ -0,0 +1,417 @@
  8609. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8610. +// Use of this source code is governed by a BSD-style license that can be
  8611. +// found in the LICENSE file.
  8612. +
  8613. +#include "script_injection_manager.h"
  8614. +
  8615. +#include <memory>
  8616. +#include <utility>
  8617. +
  8618. +#include "base/auto_reset.h"
  8619. +#include "base/bind.h"
  8620. +#include "base/feature_list.h"
  8621. +#include "base/memory/weak_ptr.h"
  8622. +#include "base/threading/thread_task_runner_handle.h"
  8623. +#include "base/values.h"
  8624. +#include "base/logging.h"
  8625. +#include "content/public/renderer/render_frame.h"
  8626. +#include "content/public/renderer/render_frame_observer.h"
  8627. +#include "content/public/renderer/render_thread.h"
  8628. +#include "extension_frame_helper.h"
  8629. +#include "../common/host_id.h"
  8630. +#include "script_injection.h"
  8631. +#include "scripts_run_info.h"
  8632. +#include "web_ui_injection_host.h"
  8633. +#include "ipc/ipc_message_macros.h"
  8634. +#include "third_party/blink/public/platform/web_url_error.h"
  8635. +#include "third_party/blink/public/web/web_document.h"
  8636. +#include "third_party/blink/public/web/web_frame.h"
  8637. +#include "third_party/blink/public/web/web_local_frame.h"
  8638. +#include "third_party/blink/public/web/web_view.h"
  8639. +#include "url/gurl.h"
  8640. +#include "../common/user_scripts_features.h"
  8641. +
  8642. +namespace user_scripts {
  8643. +
  8644. +namespace {
  8645. +
  8646. +// The length of time to wait after the DOM is complete to try and run user
  8647. +// scripts.
  8648. +const int kScriptIdleTimeoutInMs = 200;
  8649. +
  8650. +// Returns the RunLocation that follows |run_location|.
  8651. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  8652. + switch (run_location) {
  8653. + case UserScript::DOCUMENT_START:
  8654. + return UserScript::DOCUMENT_END;
  8655. + case UserScript::DOCUMENT_END:
  8656. + return UserScript::DOCUMENT_IDLE;
  8657. + case UserScript::DOCUMENT_IDLE:
  8658. + return UserScript::RUN_LOCATION_LAST;
  8659. + case UserScript::UNDEFINED:
  8660. + case UserScript::RUN_DEFERRED:
  8661. + case UserScript::BROWSER_DRIVEN:
  8662. + case UserScript::RUN_LOCATION_LAST:
  8663. + break;
  8664. + }
  8665. + NOTREACHED();
  8666. + return UserScript::RUN_LOCATION_LAST;
  8667. +}
  8668. +
  8669. +} // namespace
  8670. +
  8671. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  8672. + public:
  8673. + RFOHelper(content::RenderFrame* render_frame,
  8674. + ScriptInjectionManager* manager);
  8675. + ~RFOHelper() override;
  8676. +
  8677. + // commit @9f2aac4
  8678. + void Initialize();
  8679. +
  8680. + private:
  8681. + // RenderFrameObserver implementation.
  8682. + void DidCreateNewDocument() override;
  8683. + void DidCreateDocumentElement() override;
  8684. + void DidFailProvisionalLoad() override;
  8685. + void DidDispatchDOMContentLoadedEvent() override;
  8686. + void WillDetach() override;
  8687. + void OnDestruct() override;
  8688. + void OnStop() override;
  8689. +
  8690. + // Tells the ScriptInjectionManager to run tasks associated with
  8691. + // document_idle.
  8692. + void RunIdle();
  8693. +
  8694. + void StartInjectScripts(UserScript::RunLocation run_location);
  8695. +
  8696. + // Indicate that the frame is no longer valid because it is starting
  8697. + // a new load or closing.
  8698. + void InvalidateAndResetFrame(bool force_reset);
  8699. +
  8700. + // The owning ScriptInjectionManager.
  8701. + ScriptInjectionManager* manager_;
  8702. +
  8703. + bool should_run_idle_ = true; // commit @9f2aac4
  8704. +
  8705. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  8706. +};
  8707. +
  8708. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  8709. + ScriptInjectionManager* manager)
  8710. + : content::RenderFrameObserver(render_frame),
  8711. + manager_(manager),
  8712. + should_run_idle_(true) {}
  8713. +
  8714. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  8715. +}
  8716. +
  8717. +
  8718. +void ScriptInjectionManager::RFOHelper::Initialize() {
  8719. + // Set up for the initial empty document, for which the Document created
  8720. + // events do not happen as it's already present.
  8721. + DidCreateNewDocument();
  8722. + // The initial empty document for a main frame may have scripts attached to it
  8723. + // but we do not want to invalidate the frame and lose them when the next
  8724. + // document loads. For example the IncognitoApiTest.IncognitoSplitMode test
  8725. + // does `chrome.tabs.create()` with a script to be run, which is added to the
  8726. + // frame before it navigates, so it needs to be preserved. However scripts in
  8727. + // child frames are expected to be run inside the initial empty document. For
  8728. + // example the ExecuteScriptApiTest.FrameWithHttp204 test creates a child
  8729. + // frame at about:blank and expects to run injected scripts inside it.
  8730. + // This is all quite inconsistent however tests both depend on us queuing and
  8731. + // not queueing the DOCUMENT_START events in the initial empty document.
  8732. + if (!render_frame()->IsMainFrame()) {
  8733. + DidCreateDocumentElement();
  8734. + }
  8735. +}
  8736. +
  8737. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  8738. + // A new document is going to be shown, so invalidate the old document state.
  8739. + // Don't force-reset the frame, because it is possible that a script injection
  8740. + // was scheduled before the page was loaded, e.g. by navigating to a
  8741. + // javascript: URL before the page has loaded.
  8742. + constexpr bool kForceReset = false;
  8743. + InvalidateAndResetFrame(kForceReset);
  8744. +}
  8745. +
  8746. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  8747. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8748. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  8749. +
  8750. + ExtensionFrameHelper::Get(render_frame())
  8751. + ->ScheduleAtDocumentStart(
  8752. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8753. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  8754. +}
  8755. +
  8756. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  8757. + auto it = manager_->frame_statuses_.find(render_frame());
  8758. + if (it != manager_->frame_statuses_.end() &&
  8759. + it->second == UserScript::DOCUMENT_START) {
  8760. + // Since the provisional load failed, the frame stays at its previous loaded
  8761. + // state and origin (or the parent's origin for new/about:blank frames).
  8762. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  8763. + // done loading, and avoid any deadlock in the system.
  8764. + //
  8765. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  8766. + // injections closely follow the DOMContentLoaded (and onload) events, which
  8767. + // are not triggered after a failed provisional load.
  8768. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  8769. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  8770. + constexpr bool kForceReset = true;
  8771. + InvalidateAndResetFrame(kForceReset);
  8772. + should_run_idle_ = false;
  8773. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  8774. + }
  8775. +}
  8776. +
  8777. +void ScriptInjectionManager::RFOHelper::DidDispatchDOMContentLoadedEvent() {
  8778. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8779. + LOG(INFO) << "UserScripts: DidDispatchDOMContentLoadedEvent -> DOCUMENT_END";
  8780. +
  8781. + DCHECK(content::RenderThread::Get());
  8782. + ExtensionFrameHelper::Get(render_frame())
  8783. + ->ScheduleAtDocumentEnd(
  8784. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8785. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8786. +
  8787. + // We try to run idle in two places: a delayed task here and in response to
  8788. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidDispatchDOMContentLoadedEvent()
  8789. + // corresponds to completing the document's load, whereas
  8790. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8791. + // subresources' load (but before the window.onload event). We don't want to
  8792. + // hold up script injection for a particularly slow subresource, so we set a
  8793. + // delayed task from here - but if we finish everything before that point
  8794. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8795. + // keep waiting.
  8796. + render_frame()
  8797. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8798. + ->PostDelayedTask(
  8799. + FROM_HERE,
  8800. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8801. + weak_factory_.GetWeakPtr()),
  8802. + base::Milliseconds(kScriptIdleTimeoutInMs));
  8803. +
  8804. + ExtensionFrameHelper::Get(render_frame())
  8805. + ->ScheduleAtDocumentIdle(
  8806. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8807. + weak_factory_.GetWeakPtr()));
  8808. +}
  8809. +
  8810. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8811. + // The frame is closing - invalidate.
  8812. + constexpr bool kForceReset = true;
  8813. + InvalidateAndResetFrame(kForceReset);
  8814. +}
  8815. +
  8816. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8817. + manager_->RemoveObserver(this);
  8818. +}
  8819. +
  8820. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8821. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8822. + // extension to avoid keeping the frame in a START state indefinitely which
  8823. + // leads to deadlocks.
  8824. + DidFailProvisionalLoad();
  8825. +}
  8826. +
  8827. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8828. + // Only notify the manager if the frame hasn't already had idle run since the
  8829. + // task to RunIdle() was posted.
  8830. + if (should_run_idle_) {
  8831. + should_run_idle_ = false;
  8832. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8833. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8834. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8835. + }
  8836. +}
  8837. +
  8838. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8839. + UserScript::RunLocation run_location) {
  8840. + manager_->StartInjectScripts(render_frame(), run_location);
  8841. +}
  8842. +
  8843. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8844. + bool force_reset) {
  8845. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8846. + weak_factory_.InvalidateWeakPtrs();
  8847. + // We reset to inject on idle, because the frame can be reused (in the case of
  8848. + // navigation).
  8849. + should_run_idle_ = true;
  8850. +
  8851. + // Reset the frame if either |force_reset| is true, or if the manager is
  8852. + // keeping track of the state of the frame (in which case we need to clean it
  8853. + // up).
  8854. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8855. + manager_->InvalidateForFrame(render_frame());
  8856. +}
  8857. +
  8858. +ScriptInjectionManager::ScriptInjectionManager(
  8859. + UserScriptSetManager* user_script_set_manager)
  8860. + : user_script_set_manager_(user_script_set_manager),
  8861. + user_script_set_manager_observation_(this) {
  8862. + user_script_set_manager_observation_.Observe(user_script_set_manager_);
  8863. +}
  8864. +
  8865. +ScriptInjectionManager::~ScriptInjectionManager() {
  8866. + for (const auto& injection : pending_injections_)
  8867. + injection->invalidate_render_frame();
  8868. + for (const auto& injection : running_injections_)
  8869. + injection->invalidate_render_frame();
  8870. +}
  8871. +
  8872. +void ScriptInjectionManager::OnRenderFrameCreated(
  8873. + content::RenderFrame* render_frame) {
  8874. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8875. + rfo_helpers_.back()->Initialize(); // commit @9f2aac4
  8876. +}
  8877. +
  8878. +void ScriptInjectionManager::OnInjectionFinished(
  8879. + ScriptInjection* injection) {
  8880. + auto iter =
  8881. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8882. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8883. + return injection == mode.get();
  8884. + });
  8885. + if (iter != running_injections_.end())
  8886. + running_injections_.erase(iter);
  8887. +}
  8888. +
  8889. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8890. + const std::set<HostID>& changed_hosts) {
  8891. + for (auto iter = pending_injections_.begin();
  8892. + iter != pending_injections_.end();) {
  8893. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8894. + iter = pending_injections_.erase(iter);
  8895. + else
  8896. + ++iter;
  8897. + }
  8898. +}
  8899. +
  8900. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8901. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8902. + if (iter->get() == helper) {
  8903. + rfo_helpers_.erase(iter);
  8904. + break;
  8905. + }
  8906. + }
  8907. +}
  8908. +
  8909. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8910. + // If the frame invalidated is the frame being injected into, we need to
  8911. + // note it.
  8912. + active_injection_frames_.erase(frame);
  8913. +
  8914. + for (auto iter = pending_injections_.begin();
  8915. + iter != pending_injections_.end();) {
  8916. + if ((*iter)->render_frame() == frame)
  8917. + iter = pending_injections_.erase(iter);
  8918. + else
  8919. + ++iter;
  8920. + }
  8921. +
  8922. + frame_statuses_.erase(frame);
  8923. +}
  8924. +
  8925. +void ScriptInjectionManager::StartInjectScripts(
  8926. + content::RenderFrame* frame,
  8927. + UserScript::RunLocation run_location) {
  8928. + auto iter = frame_statuses_.find(frame);
  8929. + // We also don't execute if we detect that the run location is somehow out of
  8930. + // order. This can happen if:
  8931. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8932. + // - The run location reported doesn't immediately follow the previous
  8933. + // reported run location.
  8934. + // We don't want to run because extensions may have requirements that scripts
  8935. + // running in an earlier run location have run by the time a later script
  8936. + // runs. Better to just not run.
  8937. + // Note that we check run_location > NextRunLocation() in the second clause
  8938. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8939. + // can happen multiple times, so we can receive earlier/equal run locations.
  8940. + if ((iter == frame_statuses_.end() &&
  8941. + run_location != UserScript::DOCUMENT_START) ||
  8942. + (iter != frame_statuses_.end() &&
  8943. + run_location > NextRunLocation(iter->second))) {
  8944. + // We also invalidate the frame, because the run order of pending injections
  8945. + // may also be bad.
  8946. + InvalidateForFrame(frame);
  8947. + return;
  8948. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8949. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8950. + // multiple times. Ignore the subsequent signals.
  8951. + return;
  8952. + }
  8953. +
  8954. + // Otherwise, all is right in the world, and we can get on with the
  8955. + // injections!
  8956. + frame_statuses_[frame] = run_location;
  8957. + InjectScripts(frame, run_location);
  8958. +}
  8959. +
  8960. +void ScriptInjectionManager::InjectScripts(
  8961. + content::RenderFrame* frame,
  8962. + UserScript::RunLocation run_location) {
  8963. + // Find any injections that want to run on the given frame.
  8964. + ScriptInjectionVector frame_injections;
  8965. + for (auto iter = pending_injections_.begin();
  8966. + iter != pending_injections_.end();) {
  8967. + if ((*iter)->render_frame() == frame) {
  8968. + frame_injections.push_back(std::move(*iter));
  8969. + iter = pending_injections_.erase(iter);
  8970. + } else {
  8971. + ++iter;
  8972. + }
  8973. + }
  8974. +
  8975. + // Add any injections for user scripts.
  8976. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  8977. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  8978. + run_location);
  8979. +
  8980. + // Note that we are running in |frame|.
  8981. + active_injection_frames_.insert(frame);
  8982. +
  8983. + ScriptsRunInfo scripts_run_info(frame, run_location);
  8984. +
  8985. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  8986. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  8987. + // (if a script removes its own frame, for example). If this happens, abort.
  8988. + if (!active_injection_frames_.count(frame))
  8989. + break;
  8990. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  8991. + iter = frame_injections.erase(iter);
  8992. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  8993. + }
  8994. +
  8995. + // We are done running in the frame.
  8996. + active_injection_frames_.erase(frame);
  8997. +
  8998. + scripts_run_info.LogRun(activity_logging_enabled_);
  8999. +}
  9000. +
  9001. +void ScriptInjectionManager::TryToInject(
  9002. + std::unique_ptr<ScriptInjection> injection,
  9003. + UserScript::RunLocation run_location,
  9004. + ScriptsRunInfo* scripts_run_info) {
  9005. + // Try to inject the script. If the injection is waiting (i.e., for
  9006. + // permission), add it to the list of pending injections. If the injection
  9007. + // has blocked, add it to the list of running injections.
  9008. + // The Unretained below is safe because this object owns all the
  9009. + // ScriptInjections, so is guaranteed to outlive them.
  9010. + switch (injection->TryToInject(
  9011. + run_location, scripts_run_info,
  9012. + base::BindOnce(&ScriptInjectionManager::OnInjectionFinished,
  9013. + base::Unretained(this)))) {
  9014. + case ScriptInjection::INJECTION_WAITING:
  9015. + pending_injections_.push_back(std::move(injection));
  9016. + break;
  9017. + case ScriptInjection::INJECTION_BLOCKED:
  9018. + running_injections_.push_back(std::move(injection));
  9019. + break;
  9020. + case ScriptInjection::INJECTION_FINISHED:
  9021. + break;
  9022. + }
  9023. +}
  9024. +
  9025. +} // namespace extensions
  9026. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  9027. new file mode 100755
  9028. --- /dev/null
  9029. +++ b/components/user_scripts/renderer/script_injection_manager.h
  9030. @@ -0,0 +1,102 @@
  9031. +#include <stdint.h>
  9032. +
  9033. +#include <map>
  9034. +#include <set>
  9035. +#include <string>
  9036. +#include <vector>
  9037. +
  9038. +#include "base/callback.h"
  9039. +#include "base/macros.h"
  9040. +#include "base/scoped_observation.h"
  9041. +#include "../common/user_script.h"
  9042. +#include "script_injection.h"
  9043. +#include "user_script_set_manager.h"
  9044. +
  9045. +namespace user_scripts {
  9046. +
  9047. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  9048. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  9049. +// maintaining any pending injections awaiting permission or the appropriate
  9050. +// load point, and injecting them when ready.
  9051. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  9052. + public:
  9053. + explicit ScriptInjectionManager(
  9054. + UserScriptSetManager* user_script_set_manager);
  9055. + virtual ~ScriptInjectionManager();
  9056. +
  9057. + // Notifies that a new render view has been created.
  9058. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  9059. +
  9060. + // Removes pending injections of the unloaded extension.
  9061. + //void OnExtensionUnloaded(const std::string& extension_id);
  9062. +
  9063. + void set_activity_logging_enabled(bool enabled) {
  9064. + activity_logging_enabled_ = enabled;
  9065. + }
  9066. +
  9067. + private:
  9068. + // A RenderFrameObserver implementation which watches the various render
  9069. + // frames in order to notify the ScriptInjectionManager of different
  9070. + // document load states and IPCs.
  9071. + class RFOHelper;
  9072. +
  9073. + using FrameStatusMap =
  9074. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  9075. +
  9076. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  9077. +
  9078. + // Notifies that an injection has been finished.
  9079. + void OnInjectionFinished(ScriptInjection* injection);
  9080. +
  9081. + // UserScriptSetManager::Observer implementation.
  9082. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  9083. +
  9084. + // Notifies that an RFOHelper should be removed.
  9085. + void RemoveObserver(RFOHelper* helper);
  9086. +
  9087. + // Invalidate any pending tasks associated with |frame|.
  9088. + void InvalidateForFrame(content::RenderFrame* frame);
  9089. +
  9090. + // Starts the process to inject appropriate scripts into |frame|.
  9091. + void StartInjectScripts(content::RenderFrame* frame,
  9092. + UserScript::RunLocation run_location);
  9093. +
  9094. + // Actually injects the scripts into |frame|.
  9095. + void InjectScripts(content::RenderFrame* frame,
  9096. + UserScript::RunLocation run_location);
  9097. +
  9098. + // Try to inject and store injection if it has not finished.
  9099. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  9100. + UserScript::RunLocation run_location,
  9101. + ScriptsRunInfo* scripts_run_info);
  9102. +
  9103. + // The map of active web frames to their corresponding statuses. The
  9104. + // RunLocation of the frame corresponds to the last location that has ran.
  9105. + FrameStatusMap frame_statuses_;
  9106. +
  9107. + // The frames currently being injected into, so long as that frame is valid.
  9108. + std::set<content::RenderFrame*> active_injection_frames_;
  9109. +
  9110. + // The collection of RFOHelpers.
  9111. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  9112. +
  9113. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  9114. + UserScriptSetManager* user_script_set_manager_;
  9115. +
  9116. + // Pending injections which are waiting for either the proper run location or
  9117. + // user consent.
  9118. + ScriptInjectionVector pending_injections_;
  9119. +
  9120. + // Running injections which are waiting for async callbacks from blink.
  9121. + ScriptInjectionVector running_injections_;
  9122. +
  9123. + // Whether or not dom activity should be logged for scripts injected.
  9124. + bool activity_logging_enabled_ = false;
  9125. +
  9126. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  9127. + user_script_set_manager_observation_{this};
  9128. +
  9129. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionManager);
  9130. +};
  9131. +
  9132. +}
  9133. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  9134. new file mode 100755
  9135. --- /dev/null
  9136. +++ b/components/user_scripts/renderer/script_injector.h
  9137. @@ -0,0 +1,96 @@
  9138. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9139. +// Use of this source code is governed by a BSD-style license that can be
  9140. +// found in the LICENSE file.
  9141. +
  9142. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9143. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9144. +
  9145. +#include <memory>
  9146. +#include <vector>
  9147. +
  9148. +#include "../common/constants.h"
  9149. +#include "../common/user_script.h"
  9150. +#include "third_party/blink/public/web/web_script_source.h"
  9151. +
  9152. +class InjectionHost;
  9153. +
  9154. +namespace blink {
  9155. +class WebLocalFrame;
  9156. +}
  9157. +
  9158. +namespace user_scripts {
  9159. +
  9160. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  9161. +// information about how to inject the script, including what code to inject and
  9162. +// when (run location), but without any injection logic.
  9163. +class ScriptInjector {
  9164. + public:
  9165. + // The possible reasons for not injecting the script.
  9166. + enum InjectFailureReason {
  9167. + EXTENSION_REMOVED, // The extension was removed before injection.
  9168. + NOT_ALLOWED, // The script is not allowed to inject.
  9169. + WONT_INJECT // The injection won't inject because the user rejected
  9170. + // (or just did not accept) the injection.
  9171. + };
  9172. +
  9173. + virtual ~ScriptInjector() {}
  9174. +
  9175. + // Returns the script type of this particular injection.
  9176. + virtual UserScript::InjectionType script_type() const = 0;
  9177. +
  9178. + // Returns true if the script is running inside a user gesture.
  9179. + virtual bool IsUserGesture() const = 0;
  9180. +
  9181. + // Returns the CSS origin of this injection.
  9182. + virtual absl::optional<CSSOrigin> GetCssOrigin() const = 0;
  9183. +
  9184. + // Returns the key for this injection, if it's a CSS injection.
  9185. + virtual const absl::optional<std::string> GetInjectionKey() const = 0;
  9186. +
  9187. + // Returns true if the script expects results.
  9188. + virtual bool ExpectsResults() const = 0;
  9189. +
  9190. + // Returns true if the script should inject JS source at the given
  9191. + // |run_location|.
  9192. + virtual bool ShouldInjectJs(
  9193. + UserScript::RunLocation run_location,
  9194. + const std::set<std::string>& executing_scripts) const = 0;
  9195. +
  9196. + // Returns true if the script should inject CSS at the given |run_location|.
  9197. + virtual bool ShouldInjectCss(
  9198. + UserScript::RunLocation run_location,
  9199. + const std::set<std::string>& injected_stylesheets) const = 0;
  9200. +
  9201. + // Returns the javascript sources to inject at the given |run_location|.
  9202. + // Only called if ShouldInjectJs() is true.
  9203. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  9204. + UserScript::RunLocation run_location,
  9205. + std::set<std::string>* executing_scripts,
  9206. + size_t* num_injected_js_scripts) const = 0;
  9207. +
  9208. + // Returns the css to inject at the given |run_location|.
  9209. + // Only called if ShouldInjectCss() is true.
  9210. + virtual std::vector<blink::WebString> GetCssSources(
  9211. + UserScript::RunLocation run_location,
  9212. + std::set<std::string>* injected_stylesheets,
  9213. + size_t* num_injected_stylesheets) const = 0;
  9214. +
  9215. + // Notifies the script that injection has completed, with a possibly-populated
  9216. + // list of results (depending on whether or not ExpectsResults() was true).
  9217. + // |render_frame| contains the render frame, or null if the frame was
  9218. + // invalidated.
  9219. + virtual void OnInjectionComplete(
  9220. + std::unique_ptr<base::Value> execution_result,
  9221. + UserScript::RunLocation run_location,
  9222. + content::RenderFrame* render_frame) = 0;
  9223. +
  9224. + // Notifies the script that injection will never occur.
  9225. + // |render_frame| contains the render frame, or null if the frame was
  9226. + // invalidated.
  9227. + virtual void OnWillNotInject(InjectFailureReason reason,
  9228. + content::RenderFrame* render_frame) = 0;
  9229. +};
  9230. +
  9231. +} // namespace extensions
  9232. +
  9233. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9234. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  9235. new file mode 100755
  9236. --- /dev/null
  9237. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  9238. @@ -0,0 +1,31 @@
  9239. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9240. +// Use of this source code is governed by a BSD-style license that can be
  9241. +// found in the LICENSE file.
  9242. +
  9243. +#include "scripts_run_info.h"
  9244. +
  9245. +#include "base/metrics/histogram_macros.h"
  9246. +#include "content/public/renderer/render_frame.h"
  9247. +#include "content/public/renderer/render_thread.h"
  9248. +#include "script_context.h"
  9249. +#include "third_party/blink/public/web/web_local_frame.h"
  9250. +
  9251. +namespace user_scripts {
  9252. +
  9253. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  9254. + UserScript::RunLocation location)
  9255. + : num_css(0u),
  9256. + num_js(0u),
  9257. + num_blocking_js(0u),
  9258. + routing_id_(render_frame->GetRoutingID()),
  9259. + run_location_(location),
  9260. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  9261. + render_frame->GetWebFrame())) {}
  9262. +
  9263. +ScriptsRunInfo::~ScriptsRunInfo() {
  9264. +}
  9265. +
  9266. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  9267. +}
  9268. +
  9269. +} // namespace extensions
  9270. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  9271. new file mode 100755
  9272. --- /dev/null
  9273. +++ b/components/user_scripts/renderer/scripts_run_info.h
  9274. @@ -0,0 +1,70 @@
  9275. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9276. +// Use of this source code is governed by a BSD-style license that can be
  9277. +// found in the LICENSE file.
  9278. +
  9279. +#ifndef USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9280. +#define USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9281. +
  9282. +#include <stddef.h>
  9283. +
  9284. +#include <map>
  9285. +#include <set>
  9286. +#include <string>
  9287. +
  9288. +#include "base/macros.h"
  9289. +#include "base/timer/elapsed_timer.h"
  9290. +#include "../common/user_script.h"
  9291. +
  9292. +namespace content {
  9293. +class RenderFrame;
  9294. +}
  9295. +
  9296. +namespace user_scripts {
  9297. +
  9298. +// A struct containing information about a script run.
  9299. +struct ScriptsRunInfo {
  9300. + // Map of extensions IDs to the executing script paths.
  9301. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  9302. +
  9303. + ScriptsRunInfo(content::RenderFrame* render_frame,
  9304. + UserScript::RunLocation location);
  9305. + ~ScriptsRunInfo();
  9306. +
  9307. + // The number of CSS scripts injected.
  9308. + size_t num_css;
  9309. + // The number of JS scripts injected.
  9310. + size_t num_js;
  9311. + // The number of blocked JS scripts injected.
  9312. + size_t num_blocking_js;
  9313. + // A map of extension ids to executing script paths.
  9314. + ExecutingScriptsMap executing_scripts;
  9315. + // A map of extension ids to injected stylesheet paths.
  9316. + ExecutingScriptsMap injected_stylesheets;
  9317. + // The elapsed time since the ScriptsRunInfo was constructed.
  9318. + base::ElapsedTimer timer;
  9319. +
  9320. + // Log information about a given script run. If |send_script_activity| is
  9321. + // true, this also informs the browser of the script run.
  9322. + void LogRun(bool send_script_activity);
  9323. +
  9324. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  9325. + const base::TimeDelta& elapsed);
  9326. +
  9327. + private:
  9328. + // The routinig id to use to notify the browser of any injections. Since the
  9329. + // frame may be deleted in injection, we don't hold on to a reference to it
  9330. + // directly.
  9331. + int routing_id_;
  9332. +
  9333. + // The run location at which injection is happening.
  9334. + UserScript::RunLocation run_location_;
  9335. +
  9336. + // The url of the frame, preserved for the same reason as the routing id.
  9337. + GURL frame_url_;
  9338. +
  9339. + DISALLOW_COPY_AND_ASSIGN(ScriptsRunInfo);
  9340. +};
  9341. +
  9342. +} // namespace extensions
  9343. +
  9344. +#endif // USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9345. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  9346. new file mode 100755
  9347. --- /dev/null
  9348. +++ b/components/user_scripts/renderer/user_script_injector.cc
  9349. @@ -0,0 +1,228 @@
  9350. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9351. +// Use of this source code is governed by a BSD-style license that can be
  9352. +// found in the LICENSE file.
  9353. +
  9354. +#include "user_script_injector.h"
  9355. +
  9356. +#include <tuple>
  9357. +#include <vector>
  9358. +
  9359. +#include "base/logging.h"
  9360. +#include "base/lazy_instance.h"
  9361. +#include "content/public/common/url_constants.h"
  9362. +#include "content/public/renderer/render_frame.h"
  9363. +#include "content/public/renderer/render_thread.h"
  9364. +#include "content/public/renderer/render_view.h"
  9365. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  9366. +#include "injection_host.h"
  9367. +#include "script_context.h"
  9368. +#include "scripts_run_info.h"
  9369. +#include "third_party/blink/public/web/web_document.h"
  9370. +#include "third_party/blink/public/web/web_local_frame.h"
  9371. +#include "third_party/blink/public/web/web_script_source.h"
  9372. +#include "ui/base/resource/resource_bundle.h"
  9373. +#include "url/gurl.h"
  9374. +
  9375. +namespace user_scripts {
  9376. +
  9377. +namespace {
  9378. +
  9379. +struct RoutingInfoKey {
  9380. + int routing_id;
  9381. + int script_id;
  9382. +
  9383. + RoutingInfoKey(int routing_id, int script_id)
  9384. + : routing_id(routing_id), script_id(script_id) {}
  9385. +
  9386. + bool operator<(const RoutingInfoKey& other) const {
  9387. + return std::tie(routing_id, script_id) <
  9388. + std::tie(other.routing_id, other.script_id);
  9389. + }
  9390. +};
  9391. +
  9392. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  9393. +
  9394. +// A map records whether a given |script_id| from a webview-added user script
  9395. +// is allowed to inject on the render of given |routing_id|.
  9396. +// Once a script is added, the decision of whether or not allowed to inject
  9397. +// won't be changed.
  9398. +// After removed by the webview, the user scipt will also be removed
  9399. +// from the render. Therefore, there won't be any query from the same
  9400. +// |script_id| and |routing_id| pair.
  9401. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  9402. +// LAZY_INSTANCE_INITIALIZER;
  9403. +
  9404. +// Greasemonkey API source that is injected with the scripts.
  9405. +struct GreasemonkeyApiJsString {
  9406. + GreasemonkeyApiJsString();
  9407. + blink::WebScriptSource GetSource() const;
  9408. +
  9409. + private:
  9410. + blink::WebString source_;
  9411. +};
  9412. +
  9413. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  9414. +// the GreasemonkeyApiJs resource.
  9415. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  9416. + std::string greasemonky_api_js(
  9417. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  9418. + IDR_GREASEMONKEY_API_JS));
  9419. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  9420. +}
  9421. +
  9422. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  9423. + return blink::WebScriptSource(source_);
  9424. +}
  9425. +
  9426. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  9427. + LAZY_INSTANCE_INITIALIZER;
  9428. +
  9429. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  9430. + const std::set<std::string>& injected_files) {
  9431. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  9432. + // Check if the script is already injected.
  9433. + if (injected_files.count(file->url().path()) == 0) {
  9434. + return true;
  9435. + }
  9436. + }
  9437. + return false;
  9438. +}
  9439. +
  9440. +} // namespace
  9441. +
  9442. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  9443. + UserScriptSet* script_list)
  9444. + : script_(script),
  9445. + user_script_set_(script_list),
  9446. + script_id_(script_->id()),
  9447. + user_script_set_observer_(this) {
  9448. + user_script_set_observer_.Observe(script_list);
  9449. +}
  9450. +
  9451. +UserScriptInjector::~UserScriptInjector() {
  9452. +}
  9453. +
  9454. +void UserScriptInjector::OnUserScriptsUpdated(
  9455. + const std::set<HostID>& changed_hosts,
  9456. + const UserScriptList& scripts) {
  9457. + // When user scripts are updated, all the old script pointers are invalidated.
  9458. + script_ = nullptr;
  9459. + // If the host causing this injection changed, then this injection
  9460. + // will be removed, and there's no guarantee the backing script still exists.
  9461. + // if (changed_hosts.count(host_id_) > 0)
  9462. + // return;
  9463. +
  9464. + for (const std::unique_ptr<UserScript>& script : scripts) {
  9465. + if (script->id() == script_id_) {
  9466. + script_ = script.get();
  9467. + break;
  9468. + }
  9469. + }
  9470. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  9471. + // should be guaranteed to exist.
  9472. + DCHECK(script_);
  9473. +}
  9474. +
  9475. +UserScript::InjectionType UserScriptInjector::script_type() const {
  9476. + return UserScript::CONTENT_SCRIPT;
  9477. +}
  9478. +
  9479. +bool UserScriptInjector::IsUserGesture() const {
  9480. + return false;
  9481. +}
  9482. +
  9483. +bool UserScriptInjector::ExpectsResults() const {
  9484. + return false;
  9485. +}
  9486. +
  9487. +absl::optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  9488. + return absl::nullopt;
  9489. +}
  9490. +
  9491. +const absl::optional<std::string> UserScriptInjector::GetInjectionKey() const {
  9492. + return absl::nullopt;
  9493. +}
  9494. +
  9495. +bool UserScriptInjector::ShouldInjectJs(
  9496. + UserScript::RunLocation run_location,
  9497. + const std::set<std::string>& executing_scripts) const {
  9498. + return script_ && script_->run_location() == run_location &&
  9499. + !script_->js_scripts().empty() &&
  9500. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  9501. +}
  9502. +
  9503. +bool UserScriptInjector::ShouldInjectCss(
  9504. + UserScript::RunLocation run_location,
  9505. + const std::set<std::string>& injected_stylesheets) const {
  9506. + return script_ && run_location == UserScript::DOCUMENT_START &&
  9507. + !script_->css_scripts().empty() &&
  9508. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  9509. +}
  9510. +
  9511. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  9512. + UserScript::RunLocation run_location,
  9513. + std::set<std::string>* executing_scripts,
  9514. + size_t* num_injected_js_scripts) const {
  9515. + DCHECK(script_);
  9516. + std::vector<blink::WebScriptSource> sources;
  9517. +
  9518. + DCHECK_EQ(script_->run_location(), run_location);
  9519. +
  9520. + const UserScript::FileList& js_scripts = script_->js_scripts();
  9521. + sources.reserve(js_scripts.size() +
  9522. + (script_->emulate_greasemonkey() ? 1 : 0));
  9523. + // Emulate Greasemonkey API for scripts that were converted to extension
  9524. + // user scripts.
  9525. + if (script_->emulate_greasemonkey())
  9526. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  9527. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  9528. + const GURL& script_url = file->url();
  9529. + // Check if the script is already injected.
  9530. + if (executing_scripts->count(script_url.path()) != 0)
  9531. + continue;
  9532. +
  9533. + sources.push_back(blink::WebScriptSource(
  9534. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  9535. + script_url));
  9536. +
  9537. + (*num_injected_js_scripts) += 1;
  9538. + executing_scripts->insert(script_url.path());
  9539. + }
  9540. +
  9541. + return sources;
  9542. +}
  9543. +
  9544. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  9545. + UserScript::RunLocation run_location,
  9546. + std::set<std::string>* injected_stylesheets,
  9547. + size_t* num_injected_stylesheets) const {
  9548. + DCHECK(script_);
  9549. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  9550. +
  9551. + std::vector<blink::WebString> sources;
  9552. +
  9553. + const UserScript::FileList& css_scripts = script_->css_scripts();
  9554. + sources.reserve(css_scripts.size());
  9555. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  9556. + const std::string& stylesheet_path = file->url().path();
  9557. + // Check if the stylesheet is already injected.
  9558. + if (injected_stylesheets->count(stylesheet_path) != 0)
  9559. + continue;
  9560. +
  9561. + sources.push_back(user_script_set_->GetCssSource(*file));
  9562. + (*num_injected_stylesheets) += 1;
  9563. + injected_stylesheets->insert(stylesheet_path);
  9564. + }
  9565. + return sources;
  9566. +}
  9567. +
  9568. +void UserScriptInjector::OnInjectionComplete(
  9569. + std::unique_ptr<base::Value> execution_result,
  9570. + UserScript::RunLocation run_location,
  9571. + content::RenderFrame* render_frame) {}
  9572. +
  9573. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  9574. + content::RenderFrame* render_frame) {
  9575. +}
  9576. +
  9577. +} // namespace extensions
  9578. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  9579. new file mode 100755
  9580. --- /dev/null
  9581. +++ b/components/user_scripts/renderer/user_script_injector.h
  9582. @@ -0,0 +1,87 @@
  9583. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9584. +// Use of this source code is governed by a BSD-style license that can be
  9585. +// found in the LICENSE file.
  9586. +
  9587. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9588. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9589. +
  9590. +#include <memory>
  9591. +#include <string>
  9592. +
  9593. +#include "base/macros.h"
  9594. +#include "base/values.h"
  9595. +#include "base/scoped_observation.h"
  9596. +#include "../common/user_script.h"
  9597. +#include "script_injection.h"
  9598. +#include "user_script_set.h"
  9599. +
  9600. +class InjectionHost;
  9601. +
  9602. +namespace blink {
  9603. +class WebLocalFrame;
  9604. +}
  9605. +
  9606. +namespace user_scripts {
  9607. +
  9608. +// A ScriptInjector for UserScripts.
  9609. +class UserScriptInjector : public ScriptInjector,
  9610. + public UserScriptSet::Observer {
  9611. + public:
  9612. + UserScriptInjector(const UserScript* user_script,
  9613. + UserScriptSet* user_script_set);
  9614. + ~UserScriptInjector() override;
  9615. +
  9616. + private:
  9617. + // UserScriptSet::Observer implementation.
  9618. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9619. + const UserScriptList& scripts) override;
  9620. +
  9621. + // ScriptInjector implementation.
  9622. + UserScript::InjectionType script_type() const override;
  9623. + bool IsUserGesture() const override;
  9624. + absl::optional<CSSOrigin> GetCssOrigin() const override;
  9625. + const absl::optional<std::string> GetInjectionKey() const override;
  9626. + bool ExpectsResults() const override;
  9627. + bool ShouldInjectJs(
  9628. + UserScript::RunLocation run_location,
  9629. + const std::set<std::string>& executing_scripts) const override;
  9630. + bool ShouldInjectCss(
  9631. + UserScript::RunLocation run_location,
  9632. + const std::set<std::string>& injected_stylesheets) const override;
  9633. + std::vector<blink::WebScriptSource> GetJsSources(
  9634. + UserScript::RunLocation run_location,
  9635. + std::set<std::string>* executing_scripts,
  9636. + size_t* num_injected_js_scripts) const override;
  9637. + std::vector<blink::WebString> GetCssSources(
  9638. + UserScript::RunLocation run_location,
  9639. + std::set<std::string>* injected_stylesheets,
  9640. + size_t* num_injected_stylesheets) const override;
  9641. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  9642. + UserScript::RunLocation run_location,
  9643. + content::RenderFrame* render_frame) override;
  9644. + void OnWillNotInject(InjectFailureReason reason,
  9645. + content::RenderFrame* render_frame) override;
  9646. +
  9647. + // The associated user script. Owned by the UserScriptInjector that created
  9648. + // this object.
  9649. + const UserScript* script_;
  9650. +
  9651. + // The UserScriptSet that eventually owns the UserScript this
  9652. + // UserScriptInjector points to.
  9653. + // Outlives |this|.
  9654. + UserScriptSet* const user_script_set_;
  9655. +
  9656. + // The id of the associated user script. We cache this because when we update
  9657. + // the |script_| associated with this injection, the old referance may be
  9658. + // deleted.
  9659. + int script_id_;
  9660. +
  9661. + base::ScopedObservation<UserScriptSet, UserScriptSet::Observer>
  9662. + user_script_set_observer_{this};
  9663. +
  9664. + DISALLOW_COPY_AND_ASSIGN(UserScriptInjector);
  9665. +};
  9666. +
  9667. +} // namespace extensions
  9668. +
  9669. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9670. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  9671. new file mode 100755
  9672. --- /dev/null
  9673. +++ b/components/user_scripts/renderer/user_script_set.cc
  9674. @@ -0,0 +1,262 @@
  9675. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9676. +// Use of this source code is governed by a BSD-style license that can be
  9677. +// found in the LICENSE file.
  9678. +
  9679. +#include "user_script_set.h"
  9680. +
  9681. +#include <stddef.h>
  9682. +
  9683. +#include <utility>
  9684. +
  9685. +#include "base/logging.h"
  9686. +#include "base/debug/alias.h"
  9687. +#include "base/memory/ref_counted.h"
  9688. +#include "base/strings/strcat.h"
  9689. +#include "content/public/common/url_constants.h"
  9690. +#include "content/public/renderer/render_frame.h"
  9691. +#include "content/public/renderer/render_thread.h"
  9692. +#include "injection_host.h"
  9693. +#include "script_context.h"
  9694. +#include "script_injection.h"
  9695. +#include "user_script_injector.h"
  9696. +#include "web_ui_injection_host.h"
  9697. +#include "third_party/blink/public/web/web_document.h"
  9698. +#include "third_party/blink/public/web/web_local_frame.h"
  9699. +#include "url/gurl.h"
  9700. +#include "../common/user_scripts_features.h"
  9701. +
  9702. +namespace user_scripts {
  9703. +
  9704. +namespace {
  9705. +
  9706. +// These two strings are injected before and after the Greasemonkey API and
  9707. +// user script to wrap it in an anonymous scope.
  9708. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  9709. +const char kUserScriptTail[] = "\n})(window);";
  9710. +// Maximum number of total content scripts we allow (across all extensions).
  9711. +// The limit exists to diagnose https://crbug.com/723381. The number is
  9712. +// arbitrarily chosen.
  9713. +// TODO(lazyboy): Remove when the bug is fixed.
  9714. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  9715. +
  9716. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  9717. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  9718. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  9719. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  9720. + data_source_url.spec());
  9721. + }
  9722. +
  9723. + return data_source_url;
  9724. +}
  9725. +
  9726. +} // namespace
  9727. +
  9728. +UserScriptSet::UserScriptSet() {}
  9729. +
  9730. +UserScriptSet::~UserScriptSet() {
  9731. +}
  9732. +
  9733. +void UserScriptSet::AddObserver(Observer* observer) {
  9734. + observers_.AddObserver(observer);
  9735. +}
  9736. +
  9737. +void UserScriptSet::RemoveObserver(Observer* observer) {
  9738. + observers_.RemoveObserver(observer);
  9739. +}
  9740. +
  9741. +void UserScriptSet::GetInjections(
  9742. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9743. + content::RenderFrame* render_frame,
  9744. + int tab_id,
  9745. + UserScript::RunLocation run_location,
  9746. + bool log_activity) {
  9747. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  9748. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  9749. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  9750. + script.get(), render_frame, tab_id, run_location, document_url,
  9751. + /* is_declarative, */ log_activity);
  9752. + if (injection.get())
  9753. + injections->push_back(std::move(injection));
  9754. + }
  9755. +}
  9756. +
  9757. +bool UserScriptSet::UpdateUserScripts(
  9758. + base::ReadOnlySharedMemoryRegion shared_memory,
  9759. + const std::set<HostID>& changed_hosts,
  9760. + bool whitelisted_only) {
  9761. + bool only_inject_incognito = false;
  9762. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  9763. +
  9764. + // Create the shared memory mapping.
  9765. + shared_memory_mapping_ = shared_memory.Map();
  9766. + if (!shared_memory.IsValid())
  9767. + return false;
  9768. +
  9769. + // First get the size of the memory block.
  9770. + const base::Pickle::Header* pickle_header =
  9771. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  9772. + if (!pickle_header)
  9773. + return false;
  9774. +
  9775. + // Now read in the rest of the block.
  9776. + size_t pickle_size =
  9777. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  9778. +
  9779. + // Unpickle scripts.
  9780. + uint32_t num_scripts = 0;
  9781. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9782. + if (!memory.size())
  9783. + return false;
  9784. +
  9785. + base::Pickle pickle(memory.data(), pickle_size);
  9786. + base::PickleIterator iter(pickle);
  9787. + base::debug::Alias(&pickle_size);
  9788. + CHECK(iter.ReadUInt32(&num_scripts));
  9789. +
  9790. + // Sometimes the shared memory contents seem to be corrupted
  9791. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9792. + // scripts so that we don't add OOM noise to crash reports.
  9793. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9794. +
  9795. + scripts_.clear();
  9796. + script_sources_.clear();
  9797. + scripts_.reserve(num_scripts);
  9798. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9799. + std::unique_ptr<UserScript> script(new UserScript());
  9800. + script->Unpickle(pickle, &iter);
  9801. +
  9802. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9803. + // cleared up when the last renderer or browser process drops their
  9804. + // reference to the shared memory.
  9805. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9806. + const char* body = NULL;
  9807. + int body_length = 0;
  9808. + CHECK(iter.ReadData(&body, &body_length));
  9809. + script->js_scripts()[j]->set_external_content(
  9810. + base::StringPiece(body, body_length));
  9811. + }
  9812. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9813. + const char* body = NULL;
  9814. + int body_length = 0;
  9815. + CHECK(iter.ReadData(&body, &body_length));
  9816. + script->css_scripts()[j]->set_external_content(
  9817. + base::StringPiece(body, body_length));
  9818. + }
  9819. +
  9820. + if (only_inject_incognito && !script->is_incognito_enabled())
  9821. + continue; // This script shouldn't run in an incognito tab.
  9822. +
  9823. + scripts_.push_back(std::move(script));
  9824. + }
  9825. +
  9826. + for (auto& observer : observers_)
  9827. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9828. + return true;
  9829. +}
  9830. +
  9831. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9832. + scripts_.push_back(std::move(script));
  9833. +}
  9834. +
  9835. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9836. + const UserScript* script,
  9837. + content::RenderFrame* render_frame,
  9838. + int tab_id,
  9839. + UserScript::RunLocation run_location,
  9840. + const GURL& document_url,
  9841. + //bool is_declarative,
  9842. + bool log_activity) {
  9843. + std::unique_ptr<ScriptInjection> injection;
  9844. + std::unique_ptr<const InjectionHost> injection_host;
  9845. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9846. +
  9847. + const HostID& host_id = script->host_id();
  9848. + injection_host.reset(new WebUIInjectionHost(host_id));
  9849. +
  9850. + GURL effective_document_url =
  9851. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9852. + web_frame, document_url, script->match_origin_as_fallback());
  9853. +
  9854. + bool is_subframe = web_frame->Parent();
  9855. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9856. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9857. + LOG(INFO) << "UserScripts: Match name=" << script->name() <<
  9858. + " id=" << script->host_id().id() <<
  9859. + " url=" << effective_document_url.spec();
  9860. + return injection;
  9861. + }
  9862. +
  9863. + std::unique_ptr<ScriptInjector> injector(
  9864. + new UserScriptInjector(script, this));
  9865. +
  9866. + bool inject_css = !script->css_scripts().empty() &&
  9867. + run_location == UserScript::DOCUMENT_START;
  9868. + bool inject_js =
  9869. + !script->js_scripts().empty() && script->run_location() == run_location;
  9870. + if (inject_css || inject_js) {
  9871. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9872. + std::move(injection_host), run_location,
  9873. + log_activity));
  9874. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9875. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9876. + "url=" << effective_document_url.spec();
  9877. + } else {
  9878. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9879. + if (script->run_location() != run_location)
  9880. + LOG(INFO) << "UserScripts: run location for name=" << script->name() <<
  9881. + " id=" << script->host_id().id() <<
  9882. + " current " << run_location <<
  9883. + " need " << script->run_location();
  9884. + else
  9885. + LOG(INFO) << "UserScripts: Match but no run name=" << script->name() <<
  9886. + " id=" << script->host_id().id() <<
  9887. + " url=" << effective_document_url.spec();
  9888. + }
  9889. + }
  9890. + return injection;
  9891. +}
  9892. +
  9893. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9894. + bool emulate_greasemonkey) {
  9895. + const GURL& url = file.url();
  9896. + auto iter = script_sources_.find(url);
  9897. + if (iter != script_sources_.end()) {
  9898. + return iter->second;
  9899. + }
  9900. +
  9901. + base::StringPiece script_content = file.GetContent();
  9902. + blink::WebString source;
  9903. + if (emulate_greasemonkey) {
  9904. + // We add this dumb function wrapper for user scripts to emulate what
  9905. + // Greasemonkey does. |script_content| becomes:
  9906. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9907. + std::string content =
  9908. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9909. + source = blink::WebString::FromUTF8(content);
  9910. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9911. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9912. + } else {
  9913. + source = blink::WebString::FromUTF8(script_content.data(),
  9914. + script_content.length());
  9915. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9916. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9917. + }
  9918. + script_sources_[url] = source;
  9919. + return source;
  9920. +}
  9921. +
  9922. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9923. + const GURL& url = file.url();
  9924. + auto iter = script_sources_.find(url);
  9925. + if (iter != script_sources_.end())
  9926. + return iter->second;
  9927. +
  9928. + base::StringPiece script_content = file.GetContent();
  9929. + return script_sources_
  9930. + .insert(std::make_pair(
  9931. + url, blink::WebString::FromUTF8(script_content.data(),
  9932. + script_content.length())))
  9933. + .first->second;
  9934. +}
  9935. +
  9936. +} // namespace extensions
  9937. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9938. new file mode 100755
  9939. --- /dev/null
  9940. +++ b/components/user_scripts/renderer/user_script_set.h
  9941. @@ -0,0 +1,102 @@
  9942. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9943. +// Use of this source code is governed by a BSD-style license that can be
  9944. +// found in the LICENSE file.
  9945. +
  9946. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9947. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9948. +
  9949. +#include <map>
  9950. +#include <memory>
  9951. +#include <set>
  9952. +#include <string>
  9953. +#include <vector>
  9954. +
  9955. +#include "base/macros.h"
  9956. +#include "base/memory/read_only_shared_memory_region.h"
  9957. +#include "base/observer_list.h"
  9958. +#include "../common/user_script.h"
  9959. +#include "third_party/blink/public/platform/web_string.h"
  9960. +
  9961. +class GURL;
  9962. +
  9963. +namespace content {
  9964. +class RenderFrame;
  9965. +}
  9966. +
  9967. +namespace user_scripts {
  9968. +class ScriptInjection;
  9969. +
  9970. +// The UserScriptSet is a collection of UserScripts which knows how to update
  9971. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  9972. +// inject on a page.
  9973. +class UserScriptSet {
  9974. + public:
  9975. + class Observer {
  9976. + public:
  9977. + // Called when the set of user scripts is updated. |changed_hosts| contains
  9978. + // the hosts whose scripts have been altered. Note that *all* script objects
  9979. + // are invalidated, even if they aren't in |changed_hosts|.
  9980. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9981. + const UserScriptList& scripts) = 0;
  9982. + };
  9983. +
  9984. + UserScriptSet();
  9985. + ~UserScriptSet();
  9986. +
  9987. + // Adds or removes observers.
  9988. + void AddObserver(Observer* observer);
  9989. + void RemoveObserver(Observer* observer);
  9990. + void AddScript(std::unique_ptr<UserScript> script);
  9991. +
  9992. + // Append any ScriptInjections that should run on the given |render_frame| and
  9993. + // |tab_id|, at the given |run_location|, to |injections|.
  9994. + // |extensions| is passed in to verify the corresponding extension is still
  9995. + // valid.
  9996. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9997. + content::RenderFrame* render_frame,
  9998. + int tab_id,
  9999. + UserScript::RunLocation run_location,
  10000. + bool log_activity);
  10001. +
  10002. + // Updates scripts given the shared memory region containing user scripts.
  10003. + // Returns true if the scripts were successfully updated.
  10004. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  10005. + const std::set<HostID>& changed_hosts,
  10006. + bool whitelisted_only);
  10007. +
  10008. + // Returns the contents of a script file.
  10009. + // Note that copying is cheap as this uses WebString.
  10010. + blink::WebString GetJsSource(const UserScript::File& file,
  10011. + bool emulate_greasemonkey);
  10012. + blink::WebString GetCssSource(const UserScript::File& file);
  10013. +
  10014. + private:
  10015. + // Returns a new ScriptInjection for the given |script| to execute in the
  10016. + // |render_frame|, or NULL if the script should not execute.
  10017. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  10018. + const UserScript* script,
  10019. + content::RenderFrame* render_frame,
  10020. + int tab_id,
  10021. + UserScript::RunLocation run_location,
  10022. + const GURL& document_url,
  10023. + //bool is_declarative,
  10024. + bool log_activity);
  10025. +
  10026. + // Shared memory mapping containing raw script data.
  10027. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  10028. +
  10029. + // The UserScripts this injector manages.
  10030. + UserScriptList scripts_;
  10031. +
  10032. + // Map of user script file url -> source.
  10033. + std::map<GURL, blink::WebString> script_sources_;
  10034. +
  10035. + // The associated observers.
  10036. + base::ObserverList<Observer>::Unchecked observers_;
  10037. +
  10038. + DISALLOW_COPY_AND_ASSIGN(UserScriptSet);
  10039. +};
  10040. +
  10041. +} // namespace extensions
  10042. +
  10043. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  10044. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  10045. new file mode 100755
  10046. --- /dev/null
  10047. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  10048. @@ -0,0 +1,77 @@
  10049. +#include "user_script_set_manager.h"
  10050. +
  10051. +#include "base/logging.h"
  10052. +#include "content/public/renderer/render_thread.h"
  10053. +#include "../common/host_id.h"
  10054. +#include "../common/extension_messages.h"
  10055. +#include "../common/user_scripts_features.h"
  10056. +#include "user_script_set.h"
  10057. +
  10058. +namespace user_scripts {
  10059. +
  10060. +UserScriptSetManager::UserScriptSetManager() {
  10061. + content::RenderThread::Get()->AddObserver(this);
  10062. +}
  10063. +
  10064. +UserScriptSetManager::~UserScriptSetManager() {
  10065. +}
  10066. +
  10067. +void UserScriptSetManager::AddObserver(Observer* observer) {
  10068. + observers_.AddObserver(observer);
  10069. +}
  10070. +
  10071. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  10072. + observers_.RemoveObserver(observer);
  10073. +}
  10074. +
  10075. +bool UserScriptSetManager::OnControlMessageReceived(
  10076. + const IPC::Message& message) {
  10077. + bool handled = true;
  10078. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  10079. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  10080. + IPC_MESSAGE_UNHANDLED(handled = false)
  10081. + IPC_END_MESSAGE_MAP()
  10082. + return handled;
  10083. +}
  10084. +
  10085. +void UserScriptSetManager::GetAllInjections(
  10086. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10087. + content::RenderFrame* render_frame,
  10088. + int tab_id,
  10089. + UserScript::RunLocation run_location) {
  10090. +
  10091. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10092. + LOG(INFO) << "UserScripts: GetAllInjections";
  10093. +
  10094. + // static_scripts_ is UserScriptSet
  10095. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  10096. + activity_logging_enabled_);
  10097. +}
  10098. +
  10099. +void UserScriptSetManager::OnUpdateUserScripts(
  10100. + base::ReadOnlySharedMemoryRegion shared_memory) {
  10101. + if (!shared_memory.IsValid()) {
  10102. + NOTREACHED() << "Bad scripts handle";
  10103. + return;
  10104. + }
  10105. +
  10106. + UserScriptSet* scripts = NULL;
  10107. + scripts = &static_scripts_;
  10108. +
  10109. + DCHECK(scripts);
  10110. +
  10111. + // If no hosts are included in the set, that indicates that all
  10112. + // hosts were updated. Add them all to the set so that observers and
  10113. + // individual UserScriptSets don't need to know this detail.
  10114. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  10115. + std::set<HostID> all_hosts;
  10116. + const std::set<HostID>* effective_hosts = &all_hosts;
  10117. +
  10118. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  10119. + false /*whitelisted_only*/)) {
  10120. + for (auto& observer : observers_)
  10121. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  10122. + }
  10123. +}
  10124. +
  10125. +}
  10126. \ No newline at end of file
  10127. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  10128. new file mode 100755
  10129. --- /dev/null
  10130. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  10131. @@ -0,0 +1,62 @@
  10132. +#ifndef USERSCRIPTS_RENDER_SET_MANAGER_H_
  10133. +#define USERSCRIPTS_RENDER_SET_MANAGER_H_
  10134. +
  10135. +#include <map>
  10136. +#include <set>
  10137. +#include <string>
  10138. +#include <vector>
  10139. +
  10140. +#include "base/macros.h"
  10141. +#include "base/memory/read_only_shared_memory_region.h"
  10142. +#include "base/observer_list.h"
  10143. +#include "content/public/renderer/render_thread_observer.h"
  10144. +#include "../common/host_id.h"
  10145. +#include "user_script_set.h"
  10146. +#include "script_injection.h"
  10147. +
  10148. +namespace user_scripts {
  10149. +
  10150. +class UserScriptSetManager : public content::RenderThreadObserver {
  10151. + public:
  10152. + class Observer {
  10153. + public:
  10154. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  10155. + };
  10156. +
  10157. + UserScriptSetManager();
  10158. +
  10159. + ~UserScriptSetManager() override;
  10160. +
  10161. + void AddObserver(Observer* observer);
  10162. + void RemoveObserver(Observer* observer);
  10163. +
  10164. + // Append all injections from |static_scripts| and each of
  10165. + // |programmatic_scripts_| to |injections|.
  10166. + void GetAllInjections(
  10167. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10168. + content::RenderFrame* render_frame,
  10169. + int tab_id,
  10170. + UserScript::RunLocation run_location);
  10171. +
  10172. +private:
  10173. + // content::RenderThreadObserver implementation.
  10174. + bool OnControlMessageReceived(const IPC::Message& message) override;
  10175. +
  10176. + base::ObserverList<Observer>::Unchecked observers_;
  10177. +
  10178. + // Handle the UpdateUserScripts extension message.
  10179. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  10180. + //, const HostID& host_id,
  10181. + //const std::set<HostID>& changed_hosts,
  10182. + //bool whitelisted_only);
  10183. +
  10184. + // Scripts statically defined in extension manifests.
  10185. + UserScriptSet static_scripts_;
  10186. +
  10187. + // Whether or not dom activity should be logged for scripts injected.
  10188. + bool activity_logging_enabled_ = false;
  10189. +};
  10190. +
  10191. +}
  10192. +
  10193. +#endif
  10194. \ No newline at end of file
  10195. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10196. new file mode 100755
  10197. --- /dev/null
  10198. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10199. @@ -0,0 +1,36 @@
  10200. +#include "user_scripts_dispatcher.h"
  10201. +
  10202. +#include <stddef.h>
  10203. +
  10204. +#include <algorithm>
  10205. +#include <memory>
  10206. +#include <utility>
  10207. +
  10208. +#include "content/public/renderer/render_thread.h"
  10209. +#include "extension_frame_helper.h"
  10210. +
  10211. +namespace user_scripts {
  10212. +
  10213. +// ex ChromeExtensionsDispatcherDelegate
  10214. +UserScriptsDispatcher::UserScriptsDispatcher()
  10215. + : user_script_set_manager_observer_(this) {
  10216. + user_script_set_manager_.reset(new UserScriptSetManager());
  10217. + script_injection_manager_.reset(
  10218. + new ScriptInjectionManager(user_script_set_manager_.get()));
  10219. + user_script_set_manager_observer_.Observe(user_script_set_manager_.get());
  10220. +}
  10221. +
  10222. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  10223. +}
  10224. +
  10225. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  10226. +}
  10227. +
  10228. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  10229. +}
  10230. +
  10231. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  10232. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  10233. +}
  10234. +
  10235. +}
  10236. \ No newline at end of file
  10237. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10238. new file mode 100755
  10239. --- /dev/null
  10240. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10241. @@ -0,0 +1,48 @@
  10242. +#ifndef USERSCRIPTS_RENDER_DISPATCHER_H_
  10243. +#define USERSCRIPTS_RENDER_DISPATCHER_H_
  10244. +
  10245. +#include "user_script_set_manager.h"
  10246. +#include "script_injection_manager.h"
  10247. +
  10248. +#include <stdint.h>
  10249. +
  10250. +#include <map>
  10251. +#include <memory>
  10252. +#include <set>
  10253. +#include <string>
  10254. +#include <utility>
  10255. +#include <vector>
  10256. +
  10257. +#include "base/macros.h"
  10258. +#include "base/scoped_observation.h"
  10259. +#include "content/public/renderer/render_thread_observer.h"
  10260. +#include "content/public/renderer/render_thread.h"
  10261. +#include "../common/host_id.h"
  10262. +#include "user_script_set_manager.h"
  10263. +#include "script_injection.h"
  10264. +
  10265. +namespace user_scripts {
  10266. +
  10267. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  10268. + public UserScriptSetManager::Observer {
  10269. +
  10270. + public:
  10271. + explicit UserScriptsDispatcher();
  10272. + ~UserScriptsDispatcher() override;
  10273. +
  10274. + void OnRenderThreadStarted(content::RenderThread* thread);
  10275. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  10276. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  10277. +
  10278. + private:
  10279. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  10280. +
  10281. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  10282. +
  10283. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  10284. + user_script_set_manager_observer_{this};
  10285. +};
  10286. +
  10287. +}
  10288. +
  10289. +#endif
  10290. \ No newline at end of file
  10291. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10292. new file mode 100755
  10293. --- /dev/null
  10294. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10295. @@ -0,0 +1,105 @@
  10296. +#include "user_scripts_renderer_client.h"
  10297. +
  10298. +#include <memory>
  10299. +#include <utility>
  10300. +
  10301. +#include "base/logging.h"
  10302. +#include "base/lazy_instance.h"
  10303. +#include "content/public/renderer/render_frame.h"
  10304. +#include "content/public/renderer/render_thread.h"
  10305. +#include "content/public/renderer/render_frame_visitor.h"
  10306. +#include "chrome/renderer/chrome_render_thread_observer.h"
  10307. +
  10308. +#include "../common/user_scripts_features.h"
  10309. +#include "user_scripts_dispatcher.h"
  10310. +#include "extension_frame_helper.h"
  10311. +
  10312. +namespace user_scripts {
  10313. +
  10314. +// was ChromeExtensionsRendererClient
  10315. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  10316. +
  10317. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  10318. +
  10319. +// static
  10320. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  10321. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  10322. + LAZY_INSTANCE_INITIALIZER;
  10323. + return client.Pointer();
  10324. +}
  10325. +
  10326. +void UserScriptsRendererClient::RenderThreadStarted() {
  10327. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10328. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  10329. +
  10330. + content::RenderThread* thread = content::RenderThread::Get();
  10331. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  10332. +
  10333. + dispatcher_->OnRenderThreadStarted(thread);
  10334. + thread->AddObserver(dispatcher_.get());
  10335. +}
  10336. +
  10337. +void UserScriptsRendererClient::ConfigurationUpdated() {
  10338. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10339. + LOG(INFO) << "UserScripts: Configuration Updated";
  10340. +
  10341. + struct WatchFrame : public content::RenderFrameVisitor {
  10342. + bool Visit(content::RenderFrame* frame) override {
  10343. + if (frame)
  10344. + UserScriptsRendererClient::GetInstance()->RenderFrameCreated(frame, NULL);
  10345. + return true; // Continue visiting.
  10346. + }
  10347. + };
  10348. + WatchFrame visitor = {};
  10349. + content::RenderFrame::ForEach(&visitor);
  10350. +}
  10351. +
  10352. +void UserScriptsRendererClient::RenderFrameCreated(
  10353. + content::RenderFrame* render_frame,
  10354. + service_manager::BinderRegistry* registry) {
  10355. +
  10356. + auto params = ChromeRenderThreadObserver::GetDynamicParams();
  10357. + enabled_ = params.allow_userscript;
  10358. + if (!enabled_) return;
  10359. +
  10360. + if (loaded_ == false) {
  10361. + loaded_ = true;
  10362. + new user_scripts::ExtensionFrameHelper(render_frame);
  10363. + dispatcher_->OnRenderFrameCreated(render_frame);
  10364. + }
  10365. +}
  10366. +
  10367. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  10368. + if (!enabled_ || !loaded_) return;
  10369. +
  10370. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10371. + if (!frame_helper)
  10372. + return; // The frame is invisible to user scripts.
  10373. +
  10374. + frame_helper->RunScriptsAtDocumentStart();
  10375. + // |frame_helper| and |render_frame| might be dead by now.
  10376. +}
  10377. +
  10378. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  10379. + if (!enabled_ || !loaded_) return;
  10380. +
  10381. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10382. + if (!frame_helper)
  10383. + return; // The frame is invisible to user scripts.
  10384. +
  10385. + frame_helper->RunScriptsAtDocumentEnd();
  10386. + // |frame_helper| and |render_frame| might be dead by now.
  10387. +}
  10388. +
  10389. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  10390. + if (!enabled_ || !loaded_) return;
  10391. +
  10392. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10393. + if (!frame_helper)
  10394. + return; // The frame is invisible to user scripts.
  10395. +
  10396. + frame_helper->RunScriptsAtDocumentIdle();
  10397. + // |frame_helper| and |render_frame| might be dead by now.
  10398. +}
  10399. +
  10400. +}
  10401. \ No newline at end of file
  10402. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10403. new file mode 100755
  10404. --- /dev/null
  10405. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10406. @@ -0,0 +1,36 @@
  10407. +#ifndef USERSCRIPTS_RENDER_CLIENT_H_
  10408. +#define USERSCRIPTS_RENDER_CLIENT_H_
  10409. +
  10410. +#include <memory>
  10411. +#include <string>
  10412. +
  10413. +#include "base/macros.h"
  10414. +#include "user_scripts_dispatcher.h"
  10415. +#include "services/service_manager/public/cpp/binder_registry.h"
  10416. +
  10417. +namespace user_scripts {
  10418. +
  10419. +class UserScriptsRendererClient {
  10420. + public:
  10421. + UserScriptsRendererClient();
  10422. + ~UserScriptsRendererClient();
  10423. +
  10424. + static UserScriptsRendererClient* GetInstance();
  10425. +
  10426. + void RenderThreadStarted();
  10427. + void ConfigurationUpdated();
  10428. + void RenderFrameCreated(content::RenderFrame* render_frame,
  10429. + service_manager::BinderRegistry* registry);
  10430. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  10431. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  10432. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  10433. +
  10434. + private:
  10435. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  10436. + bool enabled_ = false;
  10437. + bool loaded_ = false;
  10438. +};
  10439. +
  10440. +}
  10441. +
  10442. +#endif
  10443. \ No newline at end of file
  10444. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  10445. new file mode 100755
  10446. --- /dev/null
  10447. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  10448. @@ -0,0 +1,40 @@
  10449. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10450. +// Use of this source code is governed by a BSD-style license that can be
  10451. +// found in the LICENSE file.
  10452. +
  10453. +#include "web_ui_injection_host.h"
  10454. +#include "base/no_destructor.h"
  10455. +
  10456. +namespace {
  10457. +
  10458. +// The default secure CSP to be used in order to prevent remote scripts.
  10459. +// use "script-src 'self' 'unsafe-eval'; object-src 'self';" to enable eval
  10460. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  10461. +}
  10462. +
  10463. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  10464. + : InjectionHost(host_id),
  10465. + url_(host_id.id()) {
  10466. +}
  10467. +
  10468. +WebUIInjectionHost::~WebUIInjectionHost() {
  10469. +}
  10470. +
  10471. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  10472. + // Use the main world CSP.
  10473. + // return nullptr;
  10474. +
  10475. + // The isolated world will use its own CSP which blocks remotely hosted
  10476. + // code.
  10477. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  10478. + kDefaultSecureCSP);
  10479. + return default_isolated_world_csp.get();
  10480. +}
  10481. +
  10482. +const GURL& WebUIInjectionHost::url() const {
  10483. + return url_;
  10484. +}
  10485. +
  10486. +const std::string& WebUIInjectionHost::name() const {
  10487. + return id().id();
  10488. +}
  10489. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  10490. new file mode 100755
  10491. --- /dev/null
  10492. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  10493. @@ -0,0 +1,28 @@
  10494. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10495. +// Use of this source code is governed by a BSD-style license that can be
  10496. +// found in the LICENSE file.
  10497. +
  10498. +#ifndef USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10499. +#define USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10500. +
  10501. +#include "base/macros.h"
  10502. +#include "injection_host.h"
  10503. +
  10504. +class WebUIInjectionHost : public InjectionHost {
  10505. + public:
  10506. + WebUIInjectionHost(const HostID& host_id);
  10507. + ~WebUIInjectionHost() override;
  10508. +
  10509. + private:
  10510. + // InjectionHost:
  10511. + const std::string* GetContentSecurityPolicy() const override;
  10512. + const GURL& url() const override;
  10513. + const std::string& name() const override;
  10514. +
  10515. + private:
  10516. + GURL url_;
  10517. +
  10518. + DISALLOW_COPY_AND_ASSIGN(WebUIInjectionHost);
  10519. +};
  10520. +
  10521. +#endif // USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10522. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  10523. new file mode 100755
  10524. --- /dev/null
  10525. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  10526. @@ -0,0 +1,55 @@
  10527. +<?xml version="1.0" encoding="utf-8"?>
  10528. +<grit-part>
  10529. +
  10530. + <!-- Preferences -->
  10531. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  10532. + desc="."
  10533. + formatter_data="android_java">
  10534. + User Scripts
  10535. + </message>
  10536. +
  10537. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  10538. + Activate User Scripts
  10539. + </message>
  10540. +
  10541. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10542. + ON
  10543. + </message>
  10544. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10545. + OFF
  10546. + </message>
  10547. +
  10548. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10549. + Add script
  10550. + </message>
  10551. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  10552. + Experimental support for Greasemonkey-style user scripts.
  10553. + </message>
  10554. +
  10555. + <message name="IDS_SCRIPTS_ITEM_VERSION" desc="." formatter_data="android_java">
  10556. + Version:
  10557. + </message>
  10558. + <message name="IDS_SCRIPTS_ITEM_FILENAME" desc="." formatter_data="android_java">
  10559. + File:
  10560. + </message>
  10561. + <message name="IDS_SCRIPTS_ITEM_URL" desc="." formatter_data="android_java">
  10562. + Url:
  10563. + </message>
  10564. +
  10565. + <message name="IDS_SCRIPTS_VIEW_SOURCE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10566. + View source
  10567. + </message>
  10568. +
  10569. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10570. + Only install user scripts that you have verified are secure, user scripts can steal your credentials and data.
  10571. +
  10572. +Do you want to install <ph name="FILE">%s</ph>?
  10573. + </message>
  10574. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10575. + Yes
  10576. + </message>
  10577. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10578. + No
  10579. + </message>
  10580. +
  10581. +</grit-part>
  10582. \ No newline at end of file
  10583. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  10584. --- a/tools/gritsettings/resource_ids.spec
  10585. +++ b/tools/gritsettings/resource_ids.spec
  10586. @@ -589,6 +589,12 @@
  10587. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  10588. "includes": [3720]
  10589. },
  10590. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  10591. + "includes": [6000],
  10592. + },
  10593. + "components/user_scripts/browser/resources/browser_resources.grd": {
  10594. + "includes": [6020],
  10595. + },
  10596. # END components/ section.
  10597. # START ios/ section.
  10598. --
  10599. 2.20.1