Experimental-user-scripts-support.patch 391 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681
  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 | 87 ++
  50. .../user_scripts/FragmentWindowAndroid.java | 90 ++
  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 | 208 +++++
  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 | 147 ++++
  68. .../user_scripts/browser/ui/user_scripts_ui.h | 37 +
  69. .../browser/user_script_loader.cc | 759 +++++++++++++++++
  70. .../user_scripts/browser/user_script_loader.h | 169 ++++
  71. .../browser/user_script_pref_info.cc | 34 +
  72. .../browser/user_script_pref_info.h | 72 ++
  73. .../user_scripts/browser/user_script_prefs.cc | 278 ++++++
  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 | 70 ++
  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 | 160 ++++
  92. components/user_scripts/common/user_script.cc | 329 +++++++
  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 | 91 ++
  101. .../user_scripts/renderer/injection_host.cc | 12 +
  102. .../user_scripts/renderer/injection_host.h | 41 +
  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 | 69 ++
  107. .../user_scripts/renderer/script_injection.cc | 343 ++++++++
  108. .../user_scripts/renderer/script_injection.h | 154 ++++
  109. .../renderer/script_injection_callback.cc | 25 +
  110. .../renderer/script_injection_callback.h | 38 +
  111. .../renderer/script_injection_manager.cc | 417 +++++++++
  112. .../renderer/script_injection_manager.h | 101 +++
  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 | 69 ++
  116. .../renderer/user_script_injector.cc | 228 +++++
  117. .../renderer/user_script_injector.h | 86 ++
  118. .../user_scripts/renderer/user_script_set.cc | 262 ++++++
  119. .../user_scripts/renderer/user_script_set.h | 101 +++
  120. .../renderer/user_script_set_manager.cc | 77 ++
  121. .../renderer/user_script_set_manager.h | 61 ++
  122. .../renderer/user_scripts_dispatcher.cc | 36 +
  123. .../renderer/user_scripts_dispatcher.h | 49 ++
  124. .../renderer/user_scripts_renderer_client.cc | 105 +++
  125. .../renderer/user_scripts_renderer_client.h | 37 +
  126. .../renderer/web_ui_injection_host.cc | 40 +
  127. .../renderer/web_ui_injection_host.h | 27 +
  128. .../strings/userscripts_strings.grdp | 55 ++
  129. tools/gritsettings/resource_ids.spec | 6 +
  130. 111 files changed, 9632 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. @@ -267,6 +267,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. @@ -556,6 +560,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. @@ -70,6 +70,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. @@ -420,6 +421,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. @@ -122,6 +122,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. @@ -322,6 +324,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. @@ -3486,6 +3486,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. @@ -150,6 +150,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. @@ -6712,6 +6713,10 @@ const FeatureEntry kFeatureEntries[] = {
  332. FEATURE_VALUE_TYPE(chromeos::features::kClipboardHistoryScreenshotNudge)},
  333. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  334. + {"enable-userscripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  335. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  336. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  337. +
  338. #if BUILDFLAG(IS_WIN)
  339. {"enable-media-foundation-video-capture",
  340. flag_descriptions::kEnableMediaFoundationVideoCaptureName,
  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. @@ -4682,7 +4682,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 BUILDFLAG(IS_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. @@ -5602,6 +5602,11 @@ const char kDesktopDetailedLanguageSettingsDescription[] =
  358. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
  359. // BUILDFLAG(IS_FUCHSIA)
  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 BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_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. @@ -3244,6 +3244,9 @@ extern const char kDesktopDetailedLanguageSettingsDescription[];
  372. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
  373. // defined (OS_FUCHSIA)
  374. +extern const char kEnableLoggingUserScriptsName[];
  375. +extern const char kEnableLoggingUserScriptsDescription[];
  376. +
  377. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_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. @@ -236,6 +236,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 // BUILDFLAG(IS_ANDROID)
  389. #include "chrome/browser/cart/cart_service.h"
  390. #include "chrome/browser/device_api/device_service_impl.h"
  391. @@ -1275,6 +1276,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. @@ -235,6 +235,8 @@
  413. #include "chrome/browser/ui/cocoa/screentime/screentime_features.h"
  414. #endif
  415. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  416. +
  417. namespace chrome {
  418. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  419. @@ -556,6 +558,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. @@ -113,6 +113,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. @@ -1635,6 +1637,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. @@ -75,6 +77,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. @@ -89,6 +92,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. @@ -236,5 +243,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. @@ -83,6 +83,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. @@ -88,6 +88,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. @@ -773,6 +774,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 !BUILDFLAG(IS_ANDROID)
  512. #if !BUILDFLAG(IS_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. @@ -110,6 +110,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. @@ -128,6 +129,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. @@ -142,6 +142,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. @@ -243,6 +243,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. @@ -415,6 +418,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. @@ -551,6 +560,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. @@ -1532,7 +1548,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. @@ -1541,7 +1564,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. @@ -1550,7 +1580,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. @@ -58,6 +58,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. @@ -255,6 +257,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. @@ -338,6 +338,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_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,87 @@
  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. + if (instance == null) Initialize();
  1238. + return instance;
  1239. + }
  1240. +
  1241. + public boolean openFile(String filePath, String mimeType, String downloadGuid,
  1242. + String originalUrl, String referrer, Uri contentUri) {
  1243. + if (UserScriptsBridge.isEnabled() == false) return false;
  1244. +
  1245. + Context context = ContextUtils.getApplicationContext();
  1246. +
  1247. + String visibleName = filePath;
  1248. + if (ContentUriUtils.isContentUri(visibleName)) {
  1249. + visibleName = ContentUriUtils.getDisplayName(contentUri, context,
  1250. + MediaStore.MediaColumns.DISPLAY_NAME);
  1251. + }
  1252. +
  1253. + if (visibleName.toUpperCase().endsWith(".USER.JS") == false) return false;
  1254. +
  1255. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  1256. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  1257. + context, UserScriptsPreferences.class.getName(),
  1258. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  1259. + IntentUtils.safeStartActivity(context, intent);
  1260. +
  1261. + return true;
  1262. + }
  1263. +
  1264. + public void openSourceFile(String scriptKey) {
  1265. + Context context = ContextUtils.getApplicationContext();
  1266. +
  1267. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("chrome://user-scripts/?key=" + scriptKey));
  1268. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1269. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1270. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1271. + intent.setPackage(context.getPackageName());
  1272. + IntentHandler.startChromeLauncherActivityForTrustedIntent(intent);
  1273. + }
  1274. +}
  1275. 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
  1276. new file mode 100644
  1277. --- /dev/null
  1278. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1279. @@ -0,0 +1,90 @@
  1280. +// Copyright 2019 The Chromium Authors. All rights reserved.
  1281. +// Use of this source code is governed by a BSD-style license that can be
  1282. +// found in the LICENSE file.
  1283. +
  1284. +package org.chromium.components.user_scripts;
  1285. +
  1286. +import android.annotation.TargetApi;
  1287. +import android.app.Activity;
  1288. +import android.content.Context;
  1289. +import android.content.Intent;
  1290. +import android.content.IntentSender;
  1291. +import android.os.Build;
  1292. +import android.view.View;
  1293. +
  1294. +import androidx.fragment.app.Fragment;
  1295. +
  1296. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  1297. +import org.chromium.ui.base.ImmutableWeakReference;
  1298. +import org.chromium.ui.base.IntentRequestTracker;
  1299. +import org.chromium.ui.base.IntentRequestTracker.Delegate;
  1300. +import org.chromium.ui.base.WindowAndroid;
  1301. +
  1302. +import java.lang.ref.WeakReference;
  1303. +
  1304. +import org.chromium.ui.permissions.ActivityAndroidPermissionDelegate;
  1305. +
  1306. +/**
  1307. + * Implements intent sending for a fragment based window. This should be created when
  1308. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  1309. + */
  1310. +public class FragmentWindowAndroid extends WindowAndroid {
  1311. + private Fragment mFragment;
  1312. +
  1313. + private static class TrackerDelegateImpl implements Delegate {
  1314. + private final Fragment mFragment;
  1315. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  1316. + // every getActivity call. It is not needed for correctness.
  1317. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  1318. +
  1319. + /**
  1320. + * Create an instance of delegate for the given fragment that will own the
  1321. + * IntentRequestTracker.
  1322. + * @param fragment The fragment that owns the IntentRequestTracker.
  1323. + */
  1324. + private TrackerDelegateImpl(Fragment fragment) {
  1325. + mFragment = fragment;
  1326. + }
  1327. +
  1328. + @Override
  1329. + public boolean startActivityForResult(Intent intent, int requestCode) {
  1330. + mFragment.startActivityForResult(intent, requestCode, null);
  1331. + return true;
  1332. + }
  1333. +
  1334. + @Override
  1335. + public boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  1336. + try {
  1337. + mFragment.startIntentSenderForResult(
  1338. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  1339. + } catch (IntentSender.SendIntentException e) {
  1340. + return false;
  1341. + }
  1342. + return true;
  1343. + }
  1344. +
  1345. + @Override
  1346. + public void finishActivity(int requestCode) {
  1347. + Activity activity = getActivity().get();
  1348. + if (activity == null) return;
  1349. + activity.finishActivity(requestCode);
  1350. + }
  1351. +
  1352. + @Override
  1353. + public final WeakReference<Activity> getActivity() {
  1354. + if (mActivityWeakRefHolder == null
  1355. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1356. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1357. + }
  1358. + return mActivityWeakRefHolder;
  1359. + }
  1360. + }
  1361. +
  1362. + FragmentWindowAndroid(Context context, Fragment fragment) {
  1363. + super(context, IntentRequestTracker.createFromDelegate(new TrackerDelegateImpl(fragment)));
  1364. + mFragment = fragment;
  1365. +
  1366. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  1367. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  1368. + }
  1369. +}
  1370. 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
  1371. new file mode 100644
  1372. --- /dev/null
  1373. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1374. @@ -0,0 +1,22 @@
  1375. +/*
  1376. + This file is part of Bromite.
  1377. +
  1378. + Bromite is free software: you can redistribute it and/or modify
  1379. + it under the terms of the GNU General Public License as published by
  1380. + the Free Software Foundation, either version 3 of the License, or
  1381. + (at your option) any later version.
  1382. +
  1383. + Bromite is distributed in the hope that it will be useful,
  1384. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1385. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1386. + GNU General Public License for more details.
  1387. +
  1388. + You should have received a copy of the GNU General Public License
  1389. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1390. +*/
  1391. +
  1392. +package org.chromium.components.user_scripts;
  1393. +
  1394. +public interface IUserScriptsUtils {
  1395. + public void openSourceFile(String scriptKey);
  1396. +}
  1397. \ No newline at end of file
  1398. 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
  1399. new file mode 100644
  1400. --- /dev/null
  1401. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1402. @@ -0,0 +1,37 @@
  1403. +/*
  1404. + This file is part of Bromite.
  1405. +
  1406. + Bromite is free software: you can redistribute it and/or modify
  1407. + it under the terms of the GNU General Public License as published by
  1408. + the Free Software Foundation, either version 3 of the License, or
  1409. + (at your option) any later version.
  1410. +
  1411. + Bromite is distributed in the hope that it will be useful,
  1412. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1413. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1414. + GNU General Public License for more details.
  1415. +
  1416. + You should have received a copy of the GNU General Public License
  1417. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1418. +*/
  1419. +
  1420. +package org.chromium.components.user_scripts;
  1421. +
  1422. +import java.time.LocalDateTime;
  1423. +
  1424. +public class ScriptInfo {
  1425. + public String Key;
  1426. + public String Name;
  1427. + public String Description;
  1428. + public String Version;
  1429. + public String FilePath;
  1430. + public String UrlSource;
  1431. +
  1432. + public boolean Enabled;
  1433. + public LocalDateTime InstallTime;
  1434. +
  1435. + public String ParserError;
  1436. + public boolean ForceDisabled;
  1437. +
  1438. + public ScriptInfo() {}
  1439. +}
  1440. 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
  1441. new file mode 100644
  1442. --- /dev/null
  1443. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1444. @@ -0,0 +1,163 @@
  1445. +/*
  1446. + This file is part of Bromite.
  1447. +
  1448. + Bromite is free software: you can redistribute it and/or modify
  1449. + it under the terms of the GNU General Public License as published by
  1450. + the Free Software Foundation, either version 3 of the License, or
  1451. + (at your option) any later version.
  1452. +
  1453. + Bromite is distributed in the hope that it will be useful,
  1454. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1455. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1456. + GNU General Public License for more details.
  1457. +
  1458. + You should have received a copy of the GNU General Public License
  1459. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1460. +*/
  1461. +
  1462. +package org.chromium.components.user_scripts;
  1463. +
  1464. +import android.content.Context;
  1465. +import android.view.LayoutInflater;
  1466. +import android.view.MotionEvent;
  1467. +import android.view.View;
  1468. +import android.view.ViewGroup;
  1469. +import android.view.accessibility.AccessibilityManager;
  1470. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1471. +import android.widget.ImageView;
  1472. +import android.widget.TextView;
  1473. +import android.widget.Switch;
  1474. +import android.widget.CompoundButton;
  1475. +import android.widget.LinearLayout;
  1476. +
  1477. +import androidx.annotation.DrawableRes;
  1478. +import androidx.annotation.NonNull;
  1479. +import androidx.core.view.ViewCompat;
  1480. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1481. +
  1482. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1483. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1484. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1485. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1486. +import org.chromium.ui.widget.ChromeImageView;
  1487. +
  1488. +import java.util.ArrayList;
  1489. +import java.util.List;
  1490. +
  1491. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1492. +
  1493. + class ItemClickListener {
  1494. + void onScriptOnOff(boolean Enabled) {}
  1495. + void onScriptClicked() {}
  1496. + }
  1497. +
  1498. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1499. + private TextView mTitle;
  1500. + private TextView mDescription;
  1501. + private TextView mVersion;
  1502. + private TextView mFile;
  1503. + private TextView mUrl;
  1504. + private TextView mError;
  1505. + private Switch mSwitch;
  1506. + private ChromeImageView mIcon;
  1507. + private LinearLayout mErrorLayout;
  1508. + private LinearLayout mUrlContainer;
  1509. +
  1510. + private ListMenuButton mMoreButton;
  1511. +
  1512. + private CompoundButton.OnCheckedChangeListener mOnOffListener;
  1513. +
  1514. + ScriptInfoRowViewHolder(View view) {
  1515. + super(view);
  1516. +
  1517. + mSwitch = view.findViewById(R.id.switch_widget);
  1518. + mTitle = view.findViewById(R.id.title);
  1519. + mDescription = view.findViewById(R.id.description);
  1520. + mVersion = view.findViewById(R.id.version);
  1521. + mFile = view.findViewById(R.id.file);
  1522. + mUrl = view.findViewById(R.id.url);
  1523. + mUrlContainer = view.findViewById(R.id.url_container);
  1524. + mError = view.findViewById(R.id.error);
  1525. + mIcon = view.findViewById(R.id.icon);
  1526. + mErrorLayout = view.findViewById(R.id.error_layout);
  1527. +
  1528. + mMoreButton = view.findViewById(R.id.more);
  1529. + }
  1530. +
  1531. + protected void updateScriptInfo(ScriptInfo item) {
  1532. + mSwitch.setOnCheckedChangeListener(null);
  1533. + mSwitch.setChecked(item.Enabled);
  1534. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1535. +
  1536. + mSwitch.setEnabled(true);
  1537. + if (item.ForceDisabled) {
  1538. + mSwitch.setEnabled(false);
  1539. + }
  1540. +
  1541. + mTitle.setText(item.Name);
  1542. + mDescription.setText(item.Description);
  1543. + mVersion.setText(item.Version);
  1544. + mFile.setText(item.Key);
  1545. + mUrl.setText(item.UrlSource);
  1546. + mError.setText(item.ParserError);
  1547. +
  1548. + mUrl.setVisibility(View.VISIBLE);
  1549. + if (item.UrlSource == null || item.UrlSource.isEmpty()) {
  1550. + mUrlContainer.setVisibility(View.GONE);
  1551. + }
  1552. + mErrorLayout.setVisibility(View.VISIBLE);
  1553. + if (item.ParserError == null || item.ParserError.isEmpty()) {
  1554. + mErrorLayout.setVisibility(View.GONE);
  1555. + }
  1556. + }
  1557. +
  1558. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1559. + mMoreButton.setVisibility(View.VISIBLE);
  1560. + mMoreButton.setDelegate(delegate);
  1561. + // Set item row end padding 0 when MenuButton is visible.
  1562. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1563. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1564. + }
  1565. +
  1566. + void setItemListener(@NonNull ItemClickListener listener) {
  1567. + mOnOffListener = (buttonView, isChecked) -> listener.onScriptOnOff(isChecked);
  1568. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1569. + itemView.setOnClickListener(view -> listener.onScriptClicked());
  1570. + }
  1571. + }
  1572. +
  1573. + ScriptListBaseAdapter(Context context) {
  1574. + super(context);
  1575. + }
  1576. +
  1577. + @Override
  1578. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1579. + View row = LayoutInflater.from(viewGroup.getContext())
  1580. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1581. + return new ScriptInfoRowViewHolder(row);
  1582. + }
  1583. +
  1584. + @Override
  1585. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1586. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1587. + }
  1588. +
  1589. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1590. + mElements = new ArrayList<>(values);
  1591. + notifyDataSetChanged();
  1592. + }
  1593. +
  1594. + @Override
  1595. + protected void setOrder(List<ScriptInfo> order) {
  1596. + }
  1597. +
  1598. + @Override
  1599. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1600. + return isPassivelyDraggable(viewHolder);
  1601. + }
  1602. +
  1603. + @Override
  1604. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1605. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1606. + }
  1607. +}
  1608. 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
  1609. new file mode 100644
  1610. --- /dev/null
  1611. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1612. @@ -0,0 +1,171 @@
  1613. +/*
  1614. + This file is part of Bromite.
  1615. +
  1616. + Bromite is free software: you can redistribute it and/or modify
  1617. + it under the terms of the GNU General Public License as published by
  1618. + the Free Software Foundation, either version 3 of the License, or
  1619. + (at your option) any later version.
  1620. +
  1621. + Bromite is distributed in the hope that it will be useful,
  1622. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1623. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1624. + GNU General Public License for more details.
  1625. +
  1626. + You should have received a copy of the GNU General Public License
  1627. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1628. +*/
  1629. +
  1630. +package org.chromium.components.user_scripts;
  1631. +
  1632. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1633. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1634. +
  1635. +import android.content.Context;
  1636. +import android.content.Intent;
  1637. +import android.provider.Browser;
  1638. +import android.net.Uri;
  1639. +import android.util.AttributeSet;
  1640. +import android.widget.TextView;
  1641. +import android.widget.Toast;
  1642. +
  1643. +import androidx.preference.Preference;
  1644. +import androidx.preference.PreferenceViewHolder;
  1645. +import androidx.recyclerview.widget.DividerItemDecoration;
  1646. +import androidx.recyclerview.widget.LinearLayoutManager;
  1647. +import androidx.recyclerview.widget.RecyclerView;
  1648. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1649. +
  1650. +import org.chromium.ui.base.WindowAndroid;
  1651. +import org.chromium.ui.base.ActivityWindowAndroid;
  1652. +
  1653. +import org.chromium.base.ApplicationStatus;
  1654. +import org.chromium.base.ContextUtils;
  1655. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1656. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1657. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1658. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1659. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1660. +
  1661. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1662. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1663. +
  1664. +import java.util.List;
  1665. +
  1666. +public class ScriptListPreference extends Preference {
  1667. + private static class ScriptListAdapter
  1668. + extends ScriptListBaseAdapter {
  1669. + private final Context mContext;
  1670. +
  1671. + ScriptListAdapter(Context context) {
  1672. + super(context);
  1673. + mContext = context;
  1674. + }
  1675. +
  1676. + @Override
  1677. + public void onBindViewHolder(ViewHolder holder, int position) {
  1678. + super.onBindViewHolder(holder, position);
  1679. +
  1680. + final ScriptInfo info = getItemByPosition(position);
  1681. +
  1682. + ModelList menuItems = new ModelList();
  1683. +
  1684. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1685. + menuItems.add(buildMenuListItem(R.string.scripts_view_source, 0, 0,
  1686. + info.ParserError == null || info.ParserError.isEmpty()));
  1687. +
  1688. + ListMenu.Delegate delegate = (model) -> {
  1689. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1690. + if (textId == R.string.remove) {
  1691. + UserScriptsBridge.RemoveScript(info.Key);
  1692. + } else if (textId == R.string.scripts_view_source) {
  1693. + UserScriptsBridge.getUtils().openSourceFile(info.Key);
  1694. + }
  1695. + };
  1696. + ((ScriptInfoRowViewHolder) holder)
  1697. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1698. + ((ScriptInfoRowViewHolder) holder)
  1699. + .setItemListener(new ScriptListBaseAdapter.ItemClickListener() {
  1700. + @Override
  1701. + public void onScriptOnOff(boolean Enabled) {
  1702. + UserScriptsBridge.SetScriptEnabled(info.Key, Enabled);
  1703. + }
  1704. +
  1705. + @Override
  1706. + public void onScriptClicked() {}
  1707. + });
  1708. + }
  1709. +
  1710. + // @Override
  1711. + public void onDataUpdated(boolean enabled) {
  1712. + List<ScriptInfo> list = UserScriptsBridge.getUserScriptItems();
  1713. + if (enabled == false) {
  1714. + for (ScriptInfo script : list) {
  1715. + script.ForceDisabled = true;
  1716. + }
  1717. + }
  1718. + setDisplayedScriptInfo(list);
  1719. + }
  1720. + }
  1721. +
  1722. + private TextView mAddButton;
  1723. + private RecyclerView mRecyclerView;
  1724. + private ScriptListAdapter mAdapter;
  1725. + private FragmentWindowAndroid mWindowAndroid;
  1726. +
  1727. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1728. + super(context, attrs);
  1729. + mAdapter = new ScriptListAdapter(context);
  1730. + }
  1731. +
  1732. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1733. + mWindowAndroid = windowAndroid;
  1734. + }
  1735. +
  1736. + @Override
  1737. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1738. + super.onBindViewHolder(holder);
  1739. +
  1740. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1741. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1742. + TintedDrawable.constructTintedDrawable(
  1743. + getContext(), R.drawable.plus, R.color.default_control_color_active_baseline),
  1744. + null, null, null);
  1745. + mAddButton.setOnClickListener(view -> {
  1746. + UserScriptsBridge.SelectAndAddScriptFromFile(mWindowAndroid);
  1747. + });
  1748. +
  1749. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1750. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1751. + mRecyclerView.setLayoutManager(layoutManager);
  1752. + mRecyclerView.addItemDecoration(
  1753. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1754. + mRecyclerView.setEnabled(this.isEnabled());
  1755. + UserScriptsBridge.RegisterLoadCallback(this);
  1756. +
  1757. + // We do not want the RecyclerView to be announced by screen readers every time
  1758. + // the view is bound.
  1759. + if (mRecyclerView.getAdapter() != mAdapter) {
  1760. + mRecyclerView.setAdapter(mAdapter);
  1761. + // Initialize script list.
  1762. + mAdapter.onDataUpdated(this.isEnabled());
  1763. + }
  1764. + }
  1765. +
  1766. + @Override
  1767. + public void setEnabled (boolean enabled) {
  1768. + super.setEnabled(enabled);
  1769. + if (mRecyclerView != null) mRecyclerView.setEnabled(enabled);
  1770. + NotifyScriptsChanged();
  1771. + }
  1772. +
  1773. + public void NotifyScriptsChanged() {
  1774. + mAdapter.onDataUpdated(this.isEnabled());
  1775. + }
  1776. +
  1777. + public void OnUserScriptLoaded(boolean result, String error) {
  1778. + if (result == false) {
  1779. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1780. + toast.show();
  1781. + }
  1782. + }
  1783. +}
  1784. 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
  1785. new file mode 100644
  1786. --- /dev/null
  1787. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1788. @@ -0,0 +1,208 @@
  1789. +/*
  1790. + This file is part of Bromite.
  1791. +
  1792. + Bromite is free software: you can redistribute it and/or modify
  1793. + it under the terms of the GNU General Public License as published by
  1794. + the Free Software Foundation, either version 3 of the License, or
  1795. + (at your option) any later version.
  1796. +
  1797. + Bromite is distributed in the hope that it will be useful,
  1798. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1799. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1800. + GNU General Public License for more details.
  1801. +
  1802. + You should have received a copy of the GNU General Public License
  1803. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1804. +*/
  1805. +
  1806. +package org.chromium.components.user_scripts;
  1807. +
  1808. +import java.util.ArrayList;
  1809. +import java.util.List;
  1810. +import java.lang.ref.WeakReference;
  1811. +
  1812. +import org.json.JSONArray;
  1813. +import org.json.JSONException;
  1814. +import org.json.JSONObject;
  1815. +
  1816. +import android.content.Context;
  1817. +import android.content.Intent;
  1818. +import android.net.Uri;
  1819. +import android.provider.MediaStore;
  1820. +import androidx.annotation.Nullable;
  1821. +import android.app.AlertDialog;
  1822. +import android.content.DialogInterface;
  1823. +
  1824. +import org.chromium.base.annotations.CalledByNative;
  1825. +import org.chromium.base.annotations.JNINamespace;
  1826. +import org.chromium.base.annotations.NativeMethods;
  1827. +import org.chromium.base.ContentUriUtils;
  1828. +import org.chromium.base.Log;
  1829. +import org.chromium.ui.base.WindowAndroid;
  1830. +
  1831. +import org.chromium.components.user_scripts.ScriptListPreference;
  1832. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1833. +
  1834. +@JNINamespace("user_scripts")
  1835. +public class UserScriptsBridge {
  1836. + private static final String TAG = "UserScript";
  1837. +
  1838. + static WeakReference<ScriptListPreference> observer;
  1839. +
  1840. + private static IUserScriptsUtils utilInstance;
  1841. +
  1842. + public static void registerUtils(IUserScriptsUtils instance) {
  1843. + utilInstance = instance;
  1844. + }
  1845. +
  1846. + public static IUserScriptsUtils getUtils() {
  1847. + return utilInstance;
  1848. + }
  1849. +
  1850. + public static boolean isEnabled() {
  1851. + return UserScriptsBridgeJni.get().isEnabled();
  1852. + }
  1853. +
  1854. + public static void setEnabled(boolean enabled) {
  1855. + UserScriptsBridgeJni.get().setEnabled(enabled);
  1856. + }
  1857. +
  1858. + public static void RemoveScript(String key) {
  1859. + UserScriptsBridgeJni.get().removeScript(key);
  1860. + }
  1861. +
  1862. + public static void SetScriptEnabled(String key,
  1863. + boolean enabled) {
  1864. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1865. + }
  1866. +
  1867. + public static void Reload() {
  1868. + UserScriptsBridgeJni.get().reload();
  1869. + }
  1870. +
  1871. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1872. + Context context = window.getContext().get();
  1873. +
  1874. + Intent fileSelector = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  1875. + fileSelector.addCategory(Intent.CATEGORY_OPENABLE);
  1876. + fileSelector.setType("*/*");
  1877. + fileSelector.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  1878. +
  1879. + window.showIntent(fileSelector,
  1880. + new WindowAndroid.IntentCallback() {
  1881. + @Override
  1882. + public void onIntentCompleted(int resultCode, Intent data) {
  1883. + if (data == null) return;
  1884. + Uri filePath = data.getData();
  1885. + TryToInstall(context, filePath.toString());
  1886. + }
  1887. + },
  1888. + null);
  1889. + }
  1890. +
  1891. + public static void TryToInstall(Context context, String ScriptFullPath) {
  1892. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1893. + @Override
  1894. + public void onClick(DialogInterface dialog, int which) {
  1895. + switch (which){
  1896. + case DialogInterface.BUTTON_POSITIVE:
  1897. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1898. + break;
  1899. +
  1900. + case DialogInterface.BUTTON_NEGATIVE:
  1901. + break;
  1902. + }
  1903. + }
  1904. + };
  1905. +
  1906. + String scriptName = ScriptFullPath;
  1907. + if (ContentUriUtils.isContentUri(scriptName)) {
  1908. + scriptName = ContentUriUtils.getDisplayName(Uri.parse(scriptName), context,
  1909. + MediaStore.MediaColumns.DISPLAY_NAME);
  1910. + }
  1911. +
  1912. + String message = context.getString(R.string.ask_to_install, scriptName);
  1913. +
  1914. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1915. + builder.setMessage(message)
  1916. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1917. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1918. + .show();
  1919. + }
  1920. +
  1921. + public static List<ScriptInfo> getUserScriptItems() {
  1922. + List<ScriptInfo> list = new ArrayList<>();
  1923. + try {
  1924. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1925. +
  1926. + JSONObject jsonObject = new JSONObject(json);
  1927. +
  1928. + JSONArray scripts = jsonObject.names();
  1929. + if (scripts != null) {
  1930. + Log.i(TAG, "User Scripts Loaded: %s", json);
  1931. + Log.i(TAG, "Totals scripts: %s", Integer.toString(scripts.length()));
  1932. + for (int i = 0; i < scripts.length(); i++) {
  1933. + String key = (String) scripts.get(i);
  1934. + JSONObject script = jsonObject.getJSONObject(key);
  1935. +
  1936. + ScriptInfo si = new ScriptInfo();
  1937. + si.Key = key;
  1938. + list.add(si);
  1939. +
  1940. + if(script.has("name")) si.Name = script.getString("name");
  1941. + if(script.has("description")) si.Description = script.getString("description");
  1942. + if(script.has("version")) si.Version = script.getString("version");
  1943. + if(script.has("file_path")) si.FilePath = script.getString("file_path");
  1944. + if(script.has("url_source")) si.UrlSource = script.getString("url_source");
  1945. + if(script.has("parser_error")) si.ParserError = script.getString("parser_error");
  1946. + if(script.has("force_disabled")) si.ForceDisabled = script.getBoolean("force_disabled");;
  1947. + si.Enabled = script.getBoolean("enabled");
  1948. + }
  1949. + } else {
  1950. + Log.i(TAG, "User Scripts list empty");
  1951. + }
  1952. + } catch (Exception e) {
  1953. + Log.e(TAG, "User Scripts Load Error", e.toString());
  1954. + }
  1955. + return list;
  1956. + }
  1957. +
  1958. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1959. + UserScriptsBridgeJni.get().registerLoadCallback();
  1960. + observer = new WeakReference<ScriptListPreference>(caller);
  1961. + }
  1962. +
  1963. + @CalledByNative
  1964. + private static void shouldRefreshUserScriptList() {
  1965. + ScriptListPreference reference = observer.get();
  1966. + if (reference != null) {
  1967. + reference.NotifyScriptsChanged();
  1968. + }
  1969. + }
  1970. +
  1971. + @CalledByNative
  1972. + private static void onUserScriptLoaded(boolean result, String error) {
  1973. + ScriptListPreference reference = observer.get();
  1974. + if (reference != null) {
  1975. + reference.OnUserScriptLoaded(result, error);
  1976. + }
  1977. + }
  1978. +
  1979. + @NativeMethods
  1980. + interface Natives {
  1981. + boolean isEnabled();
  1982. + void setEnabled(boolean enabled);
  1983. +
  1984. + String getScriptsInfo();
  1985. +
  1986. + void removeScript(String scriptKey);
  1987. + void setScriptEnabled(String scriptKey, boolean enabled);
  1988. +
  1989. + void reload();
  1990. + void selectAndAddScriptFromFile(WindowAndroid window);
  1991. + void tryToInstall(String scriptFullPath);
  1992. +
  1993. + void registerLoadCallback();
  1994. + }
  1995. +
  1996. +}
  1997. 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
  1998. new file mode 100755
  1999. --- /dev/null
  2000. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  2001. @@ -0,0 +1,116 @@
  2002. +/*
  2003. + This file is part of Bromite.
  2004. +
  2005. + Bromite is free software: you can redistribute it and/or modify
  2006. + it under the terms of the GNU General Public License as published by
  2007. + the Free Software Foundation, either version 3 of the License, or
  2008. + (at your option) any later version.
  2009. +
  2010. + Bromite is distributed in the hope that it will be useful,
  2011. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2012. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2013. + GNU General Public License for more details.
  2014. +
  2015. + You should have received a copy of the GNU General Public License
  2016. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2017. +*/
  2018. +
  2019. +package org.chromium.components.user_scripts;
  2020. +
  2021. +import android.app.Activity;
  2022. +import android.content.Context;
  2023. +import android.content.Intent;
  2024. +import android.os.Bundle;
  2025. +import android.provider.Browser;
  2026. +import android.net.Uri;
  2027. +import android.view.MenuItem;
  2028. +import android.view.View;
  2029. +
  2030. +import androidx.preference.Preference;
  2031. +import androidx.preference.PreferenceFragmentCompat;
  2032. +
  2033. +import org.chromium.base.Log;
  2034. +import org.chromium.ui.base.WindowAndroid;
  2035. +import org.chromium.ui.base.ActivityWindowAndroid;
  2036. +
  2037. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  2038. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  2039. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  2040. +
  2041. +import org.chromium.components.user_scripts.UserScriptsBridge;
  2042. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  2043. +
  2044. +public class UserScriptsPreferences
  2045. + extends PreferenceFragmentCompat
  2046. + implements SettingsUtils.ISupportHelpAndFeedback {
  2047. +
  2048. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  2049. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  2050. +
  2051. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  2052. +
  2053. + private FragmentWindowAndroid mWindowAndroid;
  2054. +
  2055. + @Override
  2056. + public void onDestroy() {
  2057. + if (mWindowAndroid != null) mWindowAndroid.destroy();
  2058. + super.onDestroy();
  2059. + }
  2060. +
  2061. + @Override
  2062. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  2063. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  2064. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  2065. +
  2066. + ChromeSwitchPreference enabledSwitch =
  2067. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  2068. + ScriptListPreference listPreference =
  2069. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  2070. +
  2071. + boolean enabled = UserScriptsBridge.isEnabled();
  2072. + enabledSwitch.setChecked(enabled);
  2073. + listPreference.setEnabled(enabled);
  2074. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  2075. + UserScriptsBridge.setEnabled((boolean) newValue);
  2076. + listPreference.setEnabled((boolean) newValue);
  2077. + return true;
  2078. + });
  2079. +
  2080. + mWindowAndroid = new FragmentWindowAndroid(getContext(), this);
  2081. + listPreference.setWindowAndroid(mWindowAndroid);
  2082. + }
  2083. +
  2084. + @Override
  2085. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  2086. + // handle picker callback from SelectFileDialog
  2087. + mWindowAndroid.getIntentRequestTracker().onActivityResult(requestCode, resultCode, data);
  2088. + }
  2089. +
  2090. + public void onHelpAndFeebackPressed() {
  2091. + Context context = getContext();
  2092. +
  2093. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  2094. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  2095. + // the user presses 'back' button.
  2096. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  2097. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  2098. + intent.setPackage(context.getPackageName());
  2099. + context.startActivity(intent);
  2100. + }
  2101. +
  2102. + public static Bundle createFragmentArgsForInstall(String filePath) {
  2103. + Bundle fragmentArgs = new Bundle();
  2104. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  2105. + return fragmentArgs;
  2106. + }
  2107. +
  2108. + @Override
  2109. + public void onActivityCreated(Bundle savedInstanceState) {
  2110. + super.onActivityCreated(savedInstanceState);
  2111. +
  2112. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  2113. + if (scriptToInstall != null) {
  2114. + UserScriptsBridge.TryToInstall(getContext(), scriptToInstall);
  2115. + }
  2116. + }
  2117. +}
  2118. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  2119. new file mode 100644
  2120. --- /dev/null
  2121. +++ b/components/user_scripts/android/java_sources.gni
  2122. @@ -0,0 +1,18 @@
  2123. +# This file is part of Bromite.
  2124. +
  2125. +# Bromite is free software: you can redistribute it and/or modify
  2126. +# it under the terms of the GNU General Public License as published by
  2127. +# the Free Software Foundation, either version 3 of the License, or
  2128. +# (at your option) any later version.
  2129. +
  2130. +# Bromite is distributed in the hope that it will be useful,
  2131. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2132. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2133. +# GNU General Public License for more details.
  2134. +
  2135. +# You should have received a copy of the GNU General Public License
  2136. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2137. +
  2138. +userscripts_java_sources = [
  2139. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  2140. +]
  2141. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  2142. new file mode 100644
  2143. --- /dev/null
  2144. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  2145. @@ -0,0 +1,173 @@
  2146. +/*
  2147. + This file is part of Bromite.
  2148. +
  2149. + Bromite is free software: you can redistribute it and/or modify
  2150. + it under the terms of the GNU General Public License as published by
  2151. + the Free Software Foundation, either version 3 of the License, or
  2152. + (at your option) any later version.
  2153. +
  2154. + Bromite is distributed in the hope that it will be useful,
  2155. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2156. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2157. + GNU General Public License for more details.
  2158. +
  2159. + You should have received a copy of the GNU General Public License
  2160. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2161. +*/
  2162. +
  2163. +#include <jni.h>
  2164. +#include <algorithm>
  2165. +#include <string>
  2166. +#include <vector>
  2167. +#include <sstream>
  2168. +#include <iterator>
  2169. +
  2170. +#include "base/android/callback_android.h"
  2171. +#include "base/android/jni_android.h"
  2172. +#include "base/android/jni_array.h"
  2173. +#include "base/android/jni_string.h"
  2174. +#include "base/android/scoped_java_ref.h"
  2175. +#include "ui/android/window_android.h"
  2176. +
  2177. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  2178. +#include "../browser/userscripts_browser_client.h"
  2179. +#include "user_scripts_bridge.h"
  2180. +
  2181. +using base::android::AttachCurrentThread;
  2182. +using base::android::ConvertJavaStringToUTF8;
  2183. +using base::android::ConvertUTF16ToJavaString;
  2184. +using base::android::ConvertUTF8ToJavaString;
  2185. +using base::android::JavaParamRef;
  2186. +using base::android::JavaRef;
  2187. +using base::android::ScopedJavaGlobalRef;
  2188. +using base::android::ScopedJavaLocalRef;
  2189. +using content::BrowserContext;
  2190. +
  2191. +namespace {
  2192. +
  2193. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  2194. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  2195. +}
  2196. +
  2197. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  2198. + private:
  2199. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  2200. + content::BrowserContext* browser_context) override {
  2201. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  2202. + }
  2203. +
  2204. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  2205. + bool result, const std::string& error) override {
  2206. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  2207. + result, error);
  2208. + }
  2209. +
  2210. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  2211. +};
  2212. +
  2213. +CallbackObserver* g_userscripts_loader_observer = NULL;
  2214. +
  2215. +}
  2216. +
  2217. +namespace user_scripts {
  2218. +
  2219. +static jboolean JNI_UserScriptsBridge_IsEnabled(
  2220. + JNIEnv* env) {
  2221. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2222. + if (client == NULL) return false;
  2223. + return client->GetPrefs()->IsEnabled();
  2224. +}
  2225. +
  2226. +static void JNI_UserScriptsBridge_SetEnabled(
  2227. + JNIEnv* env,
  2228. + jboolean is_enabled) {
  2229. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2230. + if (client == NULL) return;
  2231. + client->GetPrefs()->SetEnabled(is_enabled);
  2232. + client->GetLoader()->StartLoad();
  2233. +}
  2234. +
  2235. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  2236. + JNIEnv* env) {
  2237. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2238. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  2239. +
  2240. + std::string json = client->GetPrefs()->GetScriptsInfo();
  2241. + return ConvertUTF8ToJavaString(env, json);
  2242. +}
  2243. +
  2244. +static void JNI_UserScriptsBridge_RemoveScript(
  2245. + JNIEnv* env,
  2246. + const JavaParamRef<jstring>& jscript_key) {
  2247. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2248. + if (client == NULL) return;
  2249. +
  2250. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2251. + client->GetLoader()->RemoveScript(script_key);
  2252. +}
  2253. +
  2254. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  2255. + JNIEnv* env,
  2256. + const JavaParamRef<jstring>& jscript_key,
  2257. + jboolean is_enabled) {
  2258. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2259. + if (client == NULL) return;
  2260. +
  2261. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2262. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  2263. +}
  2264. +
  2265. +static void JNI_UserScriptsBridge_Reload(
  2266. + JNIEnv* env) {
  2267. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2268. + if (client == NULL) return;
  2269. +
  2270. + client->GetLoader()->StartLoad();
  2271. + user_scripts::ShouldRefreshUserScriptList(env);
  2272. +}
  2273. +
  2274. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  2275. + JNIEnv* env,
  2276. + const JavaParamRef<jobject>& jwindow_android) {
  2277. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2278. + if (client == NULL) return;
  2279. +
  2280. + client->GetLoader()->SelectAndAddScriptFromFile(
  2281. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  2282. +}
  2283. +
  2284. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  2285. + const JavaParamRef<jstring>& jscript_path) {
  2286. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2287. + if (client == NULL) return;
  2288. +
  2289. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  2290. + base::FilePath path(script_path);
  2291. +
  2292. + client->GetLoader()->TryToInstall(path);
  2293. +}
  2294. +
  2295. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  2296. + JNIEnv* env) {
  2297. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2298. + if (client == NULL) return;
  2299. +
  2300. + if (g_userscripts_loader_observer == NULL) {
  2301. + g_userscripts_loader_observer = new CallbackObserver();
  2302. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  2303. + }
  2304. +}
  2305. +
  2306. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  2307. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  2308. +}
  2309. +
  2310. +static void OnUserScriptLoaded(JNIEnv* env,
  2311. + bool result, const std::string& error) {
  2312. + base::android::ScopedJavaLocalRef<jstring> j_error =
  2313. + base::android::ConvertUTF8ToJavaString(env, error);
  2314. +
  2315. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  2316. +}
  2317. +
  2318. +}
  2319. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  2320. new file mode 100644
  2321. --- /dev/null
  2322. +++ b/components/user_scripts/android/user_scripts_bridge.h
  2323. @@ -0,0 +1,31 @@
  2324. +/*
  2325. + This file is part of Bromite.
  2326. +
  2327. + Bromite is free software: you can redistribute it and/or modify
  2328. + it under the terms of the GNU General Public License as published by
  2329. + the Free Software Foundation, either version 3 of the License, or
  2330. + (at your option) any later version.
  2331. +
  2332. + Bromite is distributed in the hope that it will be useful,
  2333. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2334. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2335. + GNU General Public License for more details.
  2336. +
  2337. + You should have received a copy of the GNU General Public License
  2338. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2339. +*/
  2340. +
  2341. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2342. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2343. +
  2344. +#include <jni.h>
  2345. +
  2346. +namespace user_scripts {
  2347. +
  2348. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  2349. +static void OnUserScriptLoaded(JNIEnv* env,
  2350. + bool result, const std::string& error);
  2351. +
  2352. +} // namespace user_scripts
  2353. +
  2354. +#endif
  2355. \ No newline at end of file
  2356. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  2357. new file mode 100755
  2358. --- /dev/null
  2359. +++ b/components/user_scripts/browser/BUILD.gn
  2360. @@ -0,0 +1,82 @@
  2361. +# This file is part of Bromite.
  2362. +
  2363. +# Bromite is free software: you can redistribute it and/or modify
  2364. +# it under the terms of the GNU General Public License as published by
  2365. +# the Free Software Foundation, either version 3 of the License, or
  2366. +# (at your option) any later version.
  2367. +
  2368. +# Bromite is distributed in the hope that it will be useful,
  2369. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2370. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2371. +# GNU General Public License for more details.
  2372. +
  2373. +# You should have received a copy of the GNU General Public License
  2374. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2375. +
  2376. +import("//build/config/features.gni")
  2377. +import("//tools/grit/grit_rule.gni")
  2378. +
  2379. +group("browser") {
  2380. + public_deps = [
  2381. + "//components/user_scripts/browser:browser_sources",
  2382. + ]
  2383. +}
  2384. +
  2385. +source_set("browser_sources") {
  2386. + visibility = [ "./*" ]
  2387. +
  2388. + sources = [
  2389. + "file_task_runner.cc",
  2390. + "file_task_runner.h",
  2391. + "userscripts_browser_client.cc",
  2392. + "userscripts_browser_client.h",
  2393. + "user_script_loader.cc",
  2394. + "user_script_loader.h",
  2395. + "user_script_prefs.cc",
  2396. + "user_script_prefs.h",
  2397. + "user_script_pref_info.cc",
  2398. + "user_script_pref_info.h",
  2399. + "ui/user_scripts_ui.h",
  2400. + "ui/user_scripts_ui.cc",
  2401. + ]
  2402. +
  2403. + deps = [
  2404. + ":userscripts_browser_resources",
  2405. + "//base:i18n",
  2406. + "//components/keyed_service/content",
  2407. + "//components/keyed_service/core",
  2408. + "//components/pref_registry",
  2409. + "//components/prefs",
  2410. + "//content/public/browser",
  2411. + "//crypto:platform",
  2412. + "//components/user_scripts/common",
  2413. + "//services/device/public/mojom",
  2414. + "//services/preferences/public/cpp",
  2415. + "//services/service_manager/public/cpp",
  2416. + "//third_party/blink/public/common",
  2417. + "//ui/display",
  2418. + ]
  2419. +
  2420. + public_deps = [
  2421. + "//content/public/common",
  2422. + ]
  2423. +
  2424. + configs += [
  2425. + "//build/config:precompiled_headers",
  2426. + "//build/config/compiler:wexit_time_destructors",
  2427. + ]
  2428. +}
  2429. +
  2430. +group("closure_compile") {
  2431. + deps = [ "resources/user-script-ui:closure_compile" ]
  2432. +}
  2433. +
  2434. +grit("userscripts_browser_resources") {
  2435. + source = "resources/browser_resources.grd"
  2436. +
  2437. + output_dir = "$root_gen_dir/chrome"
  2438. + outputs = [
  2439. + "grit/userscripts_browser_resources.h",
  2440. + "userscripts_browser_resources.pak",
  2441. + ]
  2442. +}
  2443. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2444. new file mode 100755
  2445. --- /dev/null
  2446. +++ b/components/user_scripts/browser/file_task_runner.cc
  2447. @@ -0,0 +1,40 @@
  2448. +/*
  2449. + This file is part of Bromite.
  2450. +
  2451. + Bromite is free software: you can redistribute it and/or modify
  2452. + it under the terms of the GNU General Public License as published by
  2453. + the Free Software Foundation, either version 3 of the License, or
  2454. + (at your option) any later version.
  2455. +
  2456. + Bromite is distributed in the hope that it will be useful,
  2457. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2458. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2459. + GNU General Public License for more details.
  2460. +
  2461. + You should have received a copy of the GNU General Public License
  2462. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2463. +*/
  2464. +
  2465. +#include "file_task_runner.h"
  2466. +
  2467. +#include "base/task/sequenced_task_runner.h"
  2468. +#include "base/task/lazy_thread_pool_task_runner.h"
  2469. +#include "base/task/task_traits.h"
  2470. +
  2471. +namespace user_scripts {
  2472. +
  2473. +namespace {
  2474. +
  2475. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2476. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2477. + base::TaskTraits(base::MayBlock(),
  2478. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2479. + base::TaskPriority::USER_VISIBLE));
  2480. +
  2481. +} // namespace
  2482. +
  2483. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2484. + return g_us_task_runner.Get();
  2485. +}
  2486. +
  2487. +} // namespace user_scripts
  2488. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2489. new file mode 100755
  2490. --- /dev/null
  2491. +++ b/components/user_scripts/browser/file_task_runner.h
  2492. @@ -0,0 +1,34 @@
  2493. +/*
  2494. + This file is part of Bromite.
  2495. +
  2496. + Bromite is free software: you can redistribute it and/or modify
  2497. + it under the terms of the GNU General Public License as published by
  2498. + the Free Software Foundation, either version 3 of the License, or
  2499. + (at your option) any later version.
  2500. +
  2501. + Bromite is distributed in the hope that it will be useful,
  2502. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2503. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2504. + GNU General Public License for more details.
  2505. +
  2506. + You should have received a copy of the GNU General Public License
  2507. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2508. +*/
  2509. +
  2510. +#ifndef USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2511. +#define USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2512. +
  2513. +#include "base/memory/ref_counted.h"
  2514. +#include "base/task/task_traits.h"
  2515. +
  2516. +namespace base {
  2517. +class SequencedTaskRunner;
  2518. +}
  2519. +
  2520. +namespace user_scripts {
  2521. +
  2522. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2523. +
  2524. +} // namespace extensions
  2525. +
  2526. +#endif // USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2527. diff --git a/components/user_scripts/browser/resources/browser_resources.grd b/components/user_scripts/browser/resources/browser_resources.grd
  2528. new file mode 100644
  2529. --- /dev/null
  2530. +++ b/components/user_scripts/browser/resources/browser_resources.grd
  2531. @@ -0,0 +1,14 @@
  2532. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  2533. + <outputs>
  2534. + <output filename="grit/userscripts_browser_resources.h" type="rc_header">
  2535. + <emit emit_type='prepend'></emit>
  2536. + </output>
  2537. + <output filename="userscripts_browser_resources.pak" type="data_package" />
  2538. + </outputs>
  2539. + <release seq="1">
  2540. + <includes>
  2541. + <include name="IDR_USER_SCRIPTS_HTML" file="user-script-ui\user-scripts-ui.html" type="BINDATA" />
  2542. + <include name="IDR_USER_SCRIPTS_JS" file="user-script-ui\user-scripts-ui.js" type="BINDATA" />
  2543. + </includes>
  2544. + </release>
  2545. +</grit>
  2546. \ No newline at end of file
  2547. diff --git a/components/user_scripts/browser/resources/user-script-ui/BUILD.gn b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2548. new file mode 100644
  2549. --- /dev/null
  2550. +++ b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2551. @@ -0,0 +1,12 @@
  2552. +import("//third_party/closure_compiler/compile_js.gni")
  2553. +
  2554. +js_type_check("closure_compile") {
  2555. + deps = [ ":view_script_source" ]
  2556. +}
  2557. +
  2558. +js_library("view_script_source") {
  2559. + deps = [
  2560. + "//ui/webui/resources/js:cr.m",
  2561. + "//ui/webui/resources/js:util.m",
  2562. + ]
  2563. +}
  2564. \ No newline at end of file
  2565. 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
  2566. new file mode 100644
  2567. --- /dev/null
  2568. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2569. @@ -0,0 +1,14 @@
  2570. +<!doctype html>
  2571. +<html lang="en">
  2572. +<head>
  2573. + <meta charset="utf-8">
  2574. + <title>Local State Debug Page</title>
  2575. + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  2576. + <script type="module" src="user-scripts-ui.js"></script>
  2577. +</head>
  2578. +<body>
  2579. + <pre id="content">
  2580. + Loading Script Source file...
  2581. + </pre>
  2582. +</body>
  2583. +</html>
  2584. \ No newline at end of file
  2585. 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
  2586. new file mode 100644
  2587. --- /dev/null
  2588. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2589. @@ -0,0 +1,9 @@
  2590. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
  2591. +import {$} from 'chrome://resources/js/util.m.js';
  2592. +
  2593. +document.addEventListener('DOMContentLoaded', function() {
  2594. + const urlParams = new URLSearchParams(window.location.search);
  2595. + sendWithPromise('requestSource', urlParams.get('key')).then(textContent => {
  2596. + $('content').textContent = textContent[0].content;
  2597. + });
  2598. +});
  2599. \ No newline at end of file
  2600. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.cc b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2601. new file mode 100644
  2602. --- /dev/null
  2603. +++ b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2604. @@ -0,0 +1,147 @@
  2605. +/*
  2606. + This file is part of Bromite.
  2607. +
  2608. + Bromite is free software: you can redistribute it and/or modify
  2609. + it under the terms of the GNU General Public License as published by
  2610. + the Free Software Foundation, either version 3 of the License, or
  2611. + (at your option) any later version.
  2612. +
  2613. + Bromite is distributed in the hope that it will be useful,
  2614. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2615. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2616. + GNU General Public License for more details.
  2617. +
  2618. + You should have received a copy of the GNU General Public License
  2619. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2620. +*/
  2621. +
  2622. +
  2623. +#include <memory>
  2624. +
  2625. +#include "base/bind.h"
  2626. +#include "base/json/json_string_value_serializer.h"
  2627. +#include "base/memory/writable_shared_memory_region.h"
  2628. +#include "base/strings/string_util.h"
  2629. +#include "base/values.h"
  2630. +
  2631. +#include "chrome/browser/browser_process.h"
  2632. +#include "chrome/browser/profiles/profile.h"
  2633. +#include "chrome/common/url_constants.h"
  2634. +#include "chrome/grit/userscripts_browser_resources.h"
  2635. +#include "components/prefs/pref_service.h"
  2636. +#include "content/public/browser/web_ui.h"
  2637. +#include "content/public/browser/web_ui_controller.h"
  2638. +#include "content/public/browser/web_ui_data_source.h"
  2639. +#include "content/public/browser/web_ui_message_handler.h"
  2640. +
  2641. +#include "user_scripts_ui.h"
  2642. +#include "../userscripts_browser_client.h"
  2643. +#include "../../common/user_script.h"
  2644. +
  2645. +namespace {
  2646. +
  2647. +class UserScriptsUIHandler : public content::WebUIMessageHandler {
  2648. + public:
  2649. + UserScriptsUIHandler(const UserScriptsUIHandler&) = delete;
  2650. + UserScriptsUIHandler& operator=(const UserScriptsUIHandler&) = delete;
  2651. + UserScriptsUIHandler();
  2652. + ~UserScriptsUIHandler() override;
  2653. +
  2654. + // content::WebUIMessageHandler:
  2655. + void RegisterMessages() override;
  2656. +
  2657. + private:
  2658. + void HandleRequestSource(base::Value::ConstListView args);
  2659. + void OnScriptsLoaded(
  2660. + const std::string callback_id,
  2661. + const std::string script_key,
  2662. + std::unique_ptr<user_scripts::UserScriptList> user_scripts);
  2663. +
  2664. + std::unique_ptr<user_scripts::UserScriptList> loaded_scripts_;
  2665. +
  2666. + base::WeakPtrFactory<UserScriptsUIHandler> weak_factory_{this};
  2667. +};
  2668. +
  2669. +UserScriptsUIHandler::UserScriptsUIHandler()
  2670. + : loaded_scripts_(new user_scripts::UserScriptList()) {
  2671. +}
  2672. +
  2673. +UserScriptsUIHandler::~UserScriptsUIHandler() {
  2674. +}
  2675. +
  2676. +void UserScriptsUIHandler::RegisterMessages() {
  2677. + web_ui()->RegisterMessageCallback(
  2678. + "requestSource",
  2679. + base::BindRepeating(&UserScriptsUIHandler::HandleRequestSource,
  2680. + base::Unretained(this)));
  2681. +}
  2682. +
  2683. +void UserScriptsUIHandler::HandleRequestSource(base::Value::ConstListView args) {
  2684. + AllowJavascript();
  2685. + if (args.size() < 2) return;
  2686. +
  2687. + std::string callback_id = args[0].GetString();
  2688. + std::string script_key = args[1].GetString();
  2689. + if (script_key.empty()) {
  2690. + std::string json = "Missing key value.";
  2691. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2692. + return;
  2693. + }
  2694. +
  2695. + user_scripts::UserScriptsBrowserClient* client = user_scripts::UserScriptsBrowserClient::GetInstance();
  2696. + if (client == NULL) {
  2697. + std::string json = "User scripts disabled.";
  2698. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2699. + } else {
  2700. + std::unique_ptr<user_scripts::UserScriptList> scripts_to_load =
  2701. + std::move(loaded_scripts_);
  2702. + scripts_to_load->clear();
  2703. +
  2704. + client->GetLoader()->LoadScripts(std::move(scripts_to_load),
  2705. + base::BindOnce(
  2706. + &UserScriptsUIHandler::OnScriptsLoaded,
  2707. + weak_factory_.GetWeakPtr(),
  2708. + callback_id, script_key)
  2709. + );
  2710. + }
  2711. +}
  2712. +
  2713. +void UserScriptsUIHandler::OnScriptsLoaded(
  2714. + const std::string callback_id,
  2715. + const std::string script_key,
  2716. + std::unique_ptr<user_scripts::UserScriptList> user_scripts) {
  2717. + loaded_scripts_ = std::move(user_scripts);
  2718. +
  2719. + base::ListValue response;
  2720. + for (const std::unique_ptr<user_scripts::UserScript>& script : *loaded_scripts_) {
  2721. + if (script->key() == script_key) {
  2722. + auto scriptData = std::make_unique<base::DictionaryValue>();
  2723. + for (const std::unique_ptr<user_scripts::UserScript::File>& js_file :
  2724. + script->js_scripts()) {
  2725. + base::StringPiece contents = js_file->GetContent();
  2726. + scriptData->SetString("content", contents.data());
  2727. + }
  2728. + response.Append(std::move(scriptData));
  2729. + }
  2730. + }
  2731. +
  2732. + ResolveJavascriptCallback(base::Value(callback_id), response);
  2733. +}
  2734. +
  2735. +} // namespace
  2736. +
  2737. +namespace user_scripts {
  2738. +
  2739. +UserScriptsUI::UserScriptsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  2740. + content::WebUIDataSource* html_source =
  2741. + content::WebUIDataSource::Create(kChromeUIUserScriptsHost);
  2742. + html_source->SetDefaultResource(IDR_USER_SCRIPTS_HTML);
  2743. + html_source->AddResourcePath("user-scripts-ui.js", IDR_USER_SCRIPTS_JS);
  2744. + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
  2745. + web_ui->AddMessageHandler(std::make_unique<UserScriptsUIHandler>());
  2746. +}
  2747. +
  2748. +UserScriptsUI::~UserScriptsUI() {
  2749. +}
  2750. +
  2751. +}
  2752. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.h b/components/user_scripts/browser/ui/user_scripts_ui.h
  2753. new file mode 100644
  2754. --- /dev/null
  2755. +++ b/components/user_scripts/browser/ui/user_scripts_ui.h
  2756. @@ -0,0 +1,37 @@
  2757. +/*
  2758. + This file is part of Bromite.
  2759. +
  2760. + Bromite is free software: you can redistribute it and/or modify
  2761. + it under the terms of the GNU General Public License as published by
  2762. + the Free Software Foundation, either version 3 of the License, or
  2763. + (at your option) any later version.
  2764. +
  2765. + Bromite is distributed in the hope that it will be useful,
  2766. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2767. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2768. + GNU General Public License for more details.
  2769. +
  2770. + You should have received a copy of the GNU General Public License
  2771. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2772. +*/
  2773. +
  2774. +#ifndef USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2775. +#define USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2776. +
  2777. +#include "content/public/browser/web_ui_controller.h"
  2778. +
  2779. +namespace user_scripts {
  2780. +
  2781. +const char kChromeUIUserScriptsHost[] = "user-scripts";
  2782. +
  2783. +class UserScriptsUI : public content::WebUIController {
  2784. + public:
  2785. + UserScriptsUI(const UserScriptsUI&) = delete;
  2786. + UserScriptsUI& operator=(const UserScriptsUI&) = delete;
  2787. + explicit UserScriptsUI(content::WebUI* web_ui);
  2788. + ~UserScriptsUI() override;
  2789. +};
  2790. +
  2791. +}
  2792. +
  2793. +#endif
  2794. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2795. new file mode 100755
  2796. --- /dev/null
  2797. +++ b/components/user_scripts/browser/user_script_loader.cc
  2798. @@ -0,0 +1,759 @@
  2799. +/*
  2800. + This file is part of Bromite.
  2801. +
  2802. + Bromite is free software: you can redistribute it and/or modify
  2803. + it under the terms of the GNU General Public License as published by
  2804. + the Free Software Foundation, either version 3 of the License, or
  2805. + (at your option) any later version.
  2806. +
  2807. + Bromite is distributed in the hope that it will be useful,
  2808. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2809. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2810. + GNU General Public License for more details.
  2811. +
  2812. + You should have received a copy of the GNU General Public License
  2813. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2814. +*/
  2815. +
  2816. +#include "user_script_loader.h"
  2817. +
  2818. +#include <stddef.h>
  2819. +
  2820. +#include <set>
  2821. +#include <string>
  2822. +#include <utility>
  2823. +
  2824. +#include "base/bind.h"
  2825. +#include "base/memory/writable_shared_memory_region.h"
  2826. +#include "base/strings/string_util.h"
  2827. +#include "base/strings/strcat.h"
  2828. +#include "base/files/file.h"
  2829. +#include "base/files/file_util.h"
  2830. +#include "base/files/file_enumerator.h"
  2831. +#include "base/i18n/file_util_icu.h"
  2832. +#include "base/path_service.h"
  2833. +#include "base/base_paths_android.h"
  2834. +#include "base/strings/utf_string_conversions.h"
  2835. +#include "base/android/content_uri_utils.h"
  2836. +#include "base/android/jni_android.h"
  2837. +#include "base/task/task_traits.h"
  2838. +#include "base/version.h"
  2839. +
  2840. +#include "crypto/sha2.h"
  2841. +#include "base/base64.h"
  2842. +
  2843. +#include "build/build_config.h"
  2844. +#include "content/public/browser/browser_context.h"
  2845. +#include "content/public/browser/browser_task_traits.h"
  2846. +#include "content/public/browser/browser_thread.h"
  2847. +#include "content/public/browser/notification_service.h"
  2848. +#include "content/public/browser/notification_types.h"
  2849. +#include "content/public/browser/render_process_host.h"
  2850. +#include "ui/shell_dialogs/select_file_dialog.h"
  2851. +#include "content/browser/file_system_access/file_system_chooser.h"
  2852. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2853. +#include "ui/android/window_android.h"
  2854. +
  2855. +#include "../common/user_scripts_features.h"
  2856. +#include "../common/extension_messages.h"
  2857. +#include "file_task_runner.h"
  2858. +#include "user_script_prefs.h"
  2859. +#include "user_script_pref_info.h"
  2860. +#include "../common/host_id.h"
  2861. +
  2862. +using content::BrowserThread;
  2863. +using content::BrowserContext;
  2864. +
  2865. +namespace user_scripts {
  2866. +
  2867. +namespace {
  2868. +
  2869. +static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2870. +static const base::StringPiece kUserScriptEnd("// ==/UserScript==");
  2871. +static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2872. +static const base::StringPiece kNameDeclaration("// @name");
  2873. +static const base::StringPiece kVersionDeclaration("// @version");
  2874. +static const base::StringPiece kDescriptionDeclaration("// @description");
  2875. +static const base::StringPiece kIncludeDeclaration("// @include");
  2876. +static const base::StringPiece kExcludeDeclaration("// @exclude");
  2877. +static const base::StringPiece kMatchDeclaration("// @match");
  2878. +static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2879. +static const base::StringPiece kRunAtDeclaration("// @run-at");
  2880. +static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2881. +static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2882. +static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2883. +static const base::StringPiece kUrlSourceDeclaration("// @url");
  2884. +static const base::StringPiece kUrlHomePageDeclaration("// @homepage");
  2885. +
  2886. +// internal use
  2887. +static const base::StringPiece kParserError("// @error");
  2888. +static const base::StringPiece kForceDisabled("// @disabled");
  2889. +
  2890. +// Helper function to parse greasesmonkey headers
  2891. +bool GetDeclarationValue(const base::StringPiece& line,
  2892. + const base::StringPiece& prefix,
  2893. + std::string* value) {
  2894. + base::StringPiece::size_type index = line.find(prefix);
  2895. + if (index == base::StringPiece::npos)
  2896. + return false;
  2897. +
  2898. + std::string temp(line.data() + index + prefix.length(),
  2899. + line.length() - index - prefix.length());
  2900. +
  2901. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2902. + return false;
  2903. +
  2904. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2905. + return true;
  2906. +}
  2907. +
  2908. +const std::u16string FileErrorString(base::File::Error error) {
  2909. + switch (error) {
  2910. + case base::File::FILE_ERROR_FAILED:
  2911. + return u"No further details.";
  2912. + case base::File::FILE_ERROR_IN_USE:
  2913. + return u"File currently in use.";
  2914. + case base::File::FILE_ERROR_EXISTS:
  2915. + return u"File already exists.";
  2916. + case base::File::FILE_ERROR_NOT_FOUND:
  2917. + return u"File not found.";
  2918. + case base::File::FILE_ERROR_ACCESS_DENIED:
  2919. + return u"Access denied.";
  2920. + case base::File::FILE_ERROR_TOO_MANY_OPENED:
  2921. + return u"Too many files open.";
  2922. + case base::File::FILE_ERROR_NO_MEMORY:
  2923. + return u"Out of memory.";
  2924. + case base::File::FILE_ERROR_NO_SPACE:
  2925. + return u"No space left on drive.";
  2926. + case base::File::FILE_ERROR_NOT_A_DIRECTORY:
  2927. + return u"Not a directory.";
  2928. + case base::File::FILE_ERROR_INVALID_OPERATION:
  2929. + return u"Invalid operation.";
  2930. + case base::File::FILE_ERROR_SECURITY:
  2931. + return u"Security error.";
  2932. + case base::File::FILE_ERROR_ABORT:
  2933. + return u"File operation aborted.";
  2934. + case base::File::FILE_ERROR_NOT_A_FILE:
  2935. + return u"The supplied path was not a file.";
  2936. + case base::File::FILE_ERROR_NOT_EMPTY:
  2937. + return u"The file was not empty.";
  2938. + case base::File::FILE_ERROR_INVALID_URL:
  2939. + return u"Invalid URL.";
  2940. + case base::File::FILE_ERROR_IO:
  2941. + return u"OS or hardware error.";
  2942. + case base::File::FILE_OK:
  2943. + return u"OK.";
  2944. + case base::File::FILE_ERROR_MAX:
  2945. + NOTREACHED();
  2946. + }
  2947. + NOTIMPLEMENTED();
  2948. + return u"Unknown error.";
  2949. +}
  2950. +
  2951. +} // namespace
  2952. +
  2953. +// static
  2954. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2955. + std::unique_ptr<UserScript>& script,
  2956. + bool *found_metadata,
  2957. + std::string& error_message) {
  2958. + // http://wiki.greasespot.net/Metadata_block
  2959. + base::StringPiece line;
  2960. + size_t line_start = 0;
  2961. + size_t line_end = line_start;
  2962. + *found_metadata = false;
  2963. +
  2964. + while (line_start < script_text.length()) {
  2965. + line_end = script_text.find('\n', line_start);
  2966. +
  2967. + // Handle the case where there is no trailing newline in the file.
  2968. + if (line_end == std::string::npos)
  2969. + line_end = script_text.length() - 1;
  2970. +
  2971. + line = base::StringPiece(script_text.data() + line_start,
  2972. + line_end - line_start);
  2973. +
  2974. + if (!*found_metadata) {
  2975. + if (base::StartsWith(line, kUserScriptBegin))
  2976. + *found_metadata = true;
  2977. + } else {
  2978. + if (base::StartsWith(line, kUserScriptEnd))
  2979. + break;
  2980. +
  2981. + std::string value;
  2982. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2983. + // We escape some characters that MatchPattern() considers special.
  2984. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2985. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2986. + script->add_glob(value);
  2987. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2988. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2989. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2990. + script->add_exclude_glob(value);
  2991. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2992. + script->set_name_space(value);
  2993. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2994. + script->set_name(value);
  2995. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2996. + base::Version version(value);
  2997. + if (version.IsValid())
  2998. + script->set_version(version.GetString());
  2999. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  3000. + script->set_description(value);
  3001. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  3002. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  3003. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  3004. + error_message = "Invalid UserScript Schema " + value;
  3005. + return false;
  3006. + }
  3007. + script->add_url_pattern(pattern);
  3008. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  3009. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  3010. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  3011. + error_message = "Invalid UserScript Schema " + value;
  3012. + return false;
  3013. + }
  3014. + script->add_exclude_url_pattern(exclude);
  3015. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  3016. + if (value == kRunAtDocumentStartValue)
  3017. + script->set_run_location(UserScript::DOCUMENT_START);
  3018. + else if (value == kRunAtDocumentEndValue)
  3019. + script->set_run_location(UserScript::DOCUMENT_END);
  3020. + else if (value == kRunAtDocumentIdleValue)
  3021. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  3022. + else {
  3023. + error_message = "Invalid RunAtDeclaration " + value;
  3024. + return false;
  3025. + }
  3026. + } else if (GetDeclarationValue(line, kUrlSourceDeclaration, &value) ||
  3027. + GetDeclarationValue(line, kUrlHomePageDeclaration, &value)) {
  3028. + script->set_url_source(value);
  3029. + } else if (GetDeclarationValue(line, kParserError, &value)) {
  3030. + script->set_parser_error(value);
  3031. + } else if (GetDeclarationValue(line, kForceDisabled, &value)) {
  3032. + script->set_force_disabled();
  3033. + }
  3034. +
  3035. + // TODO(aa): Handle more types of metadata.
  3036. + }
  3037. +
  3038. + line_start = line_end + 1;
  3039. + }
  3040. +
  3041. + // If no patterns were specified, default to @include *. This is what
  3042. + // Greasemonkey does.
  3043. + if (script->globs().empty() && script->url_patterns().is_empty())
  3044. + script->add_glob("*");
  3045. +
  3046. + return true;
  3047. +}
  3048. +
  3049. +// static
  3050. +bool LoadUserScriptFromFile(
  3051. + const base::FilePath& user_script_path, const GURL& original_url,
  3052. + std::unique_ptr<UserScript>& script,
  3053. + bool* found_metadata,
  3054. + std::u16string* error) {
  3055. +
  3056. + base::File infile;
  3057. + if (user_script_path.IsContentUri()) {
  3058. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3059. + LOG(INFO) << "UserScriptLoader: path " << user_script_path << " is a content uri";
  3060. +
  3061. + infile = OpenContentUriForRead(user_script_path);
  3062. + } else {
  3063. + infile = base::File(user_script_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  3064. + }
  3065. +
  3066. + if (!infile.IsValid()) {
  3067. + base::File::Error out_error = infile.error_details();
  3068. + *error = u"Cannot open script source. Error: " +
  3069. + FileErrorString(out_error);
  3070. + return false;
  3071. + }
  3072. +
  3073. + auto length = infile.GetLength();
  3074. + if (length<=0) {
  3075. + *error = u"File is empty.";
  3076. + return false;
  3077. + }
  3078. +
  3079. + auto buffer = std::vector<char>(length);
  3080. + int bytes_read = infile.Read(0, buffer.data(), length);
  3081. + if (bytes_read == -1) {
  3082. + *error = u"Could not read source file.";
  3083. + return false;
  3084. + }
  3085. +
  3086. + std::string content(buffer.begin(), buffer.end());
  3087. + if (!base::IsStringUTF8(content)) {
  3088. + *error = u"User script must be UTF8 encoded.";
  3089. + return false;
  3090. + }
  3091. +
  3092. + std::string detailed_error;
  3093. + bool parseResult = UserScriptLoader::ParseMetadataHeader(content, script,
  3094. + found_metadata, detailed_error);
  3095. + if (parseResult == false || *found_metadata == false) {
  3096. + std::u16string detailed_error16;
  3097. + base::UTF8ToUTF16(detailed_error.c_str(), detailed_error.length(), &detailed_error16);
  3098. + *error = base::StrCat({u"Invalid script header. ", detailed_error16});
  3099. + return false;
  3100. + }
  3101. +
  3102. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  3103. +
  3104. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  3105. + file->set_content(content);
  3106. + file->set_url(GURL(base::StrCat({"https://userscripts/file/",
  3107. + user_script_path.BaseName().value(), ".js"})));
  3108. +
  3109. + // create SHA256 of file
  3110. + char raw[crypto::kSHA256Length] = {0};
  3111. + std::string key;
  3112. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  3113. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  3114. + file->set_key(key);
  3115. +
  3116. + script->js_scripts().push_back(std::move(file));
  3117. +
  3118. + // add into key the filename
  3119. + // this value is used in ui to discriminate scripts
  3120. + script->set_key(user_script_path.BaseName().value());
  3121. + return true;
  3122. +}
  3123. +
  3124. +// static
  3125. +bool GetOrCreatePath(base::FilePath& path) {
  3126. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  3127. + path = path.AppendASCII("userscripts");
  3128. +
  3129. + // create snippets directory if not exists
  3130. + if (!base::PathExists(path)) {
  3131. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  3132. + base::File::Error error = base::File::FILE_OK;
  3133. + if (!base::CreateDirectoryAndGetError(path, &error)) {
  3134. + LOG(ERROR) <<
  3135. + "UserScriptLoader: failed to create directory: " << path
  3136. + << " with error code " << error;
  3137. + return false;
  3138. + }
  3139. + }
  3140. + return true;
  3141. +}
  3142. +
  3143. +// static
  3144. +void LoadUserScripts(UserScriptList* user_scripts_list) {
  3145. + base::FilePath path;
  3146. + if (GetOrCreatePath(path) == false) return;
  3147. +
  3148. + // enumerate all files from script path
  3149. + // we accept all files, but we check if it's a real
  3150. + // userscript
  3151. + base::FileEnumerator dir_enum(
  3152. + path,
  3153. + /*recursive=*/false, base::FileEnumerator::FILES);
  3154. + base::FilePath full_name;
  3155. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  3156. + std::unique_ptr<UserScript> userscript(new UserScript());
  3157. + userscript->set_id(UserScript::GenerateUserScriptID());
  3158. + userscript->set_host_id(HostID(HostID::HostType::EXTENSIONS,
  3159. + "_" + base::NumberToString(userscript->id())));
  3160. +
  3161. + std::u16string error;
  3162. + bool found_metadata;
  3163. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &found_metadata, &error)) {
  3164. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3165. + LOG(INFO) << "UserScriptLoader: Found user script " << userscript->name() <<
  3166. + "-" << userscript->version() <<
  3167. + "-" << userscript->description();
  3168. +
  3169. + userscript->set_file_path(full_name.AsUTF8Unsafe());
  3170. + user_scripts_list->push_back(std::move(userscript));
  3171. + } else {
  3172. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3173. + }
  3174. + }
  3175. +}
  3176. +
  3177. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  3178. + UserScriptsPrefs* prefs)
  3179. + : loaded_scripts_(new UserScriptList()),
  3180. + ready_(false),
  3181. + browser_context_(browser_context),
  3182. + prefs_(prefs) {}
  3183. +
  3184. +UserScriptLoader::~UserScriptLoader() {
  3185. + for (auto& observer : observers_)
  3186. + observer.OnUserScriptLoaderDestroyed(this);
  3187. +}
  3188. +
  3189. +void UserScriptLoader::OnRenderProcessHostCreated(
  3190. + content::RenderProcessHost* process_host) {
  3191. + if (initial_load_complete()) {
  3192. + SendUpdate(process_host, shared_memory_);
  3193. + }
  3194. +}
  3195. +
  3196. +void UserScriptLoader::SetReady(bool ready) {
  3197. + bool was_ready = ready_;
  3198. + ready_ = ready;
  3199. + if (ready_ && !was_ready)
  3200. + AttemptLoad();
  3201. +}
  3202. +
  3203. +void UserScriptLoader::AttemptLoad() {
  3204. + int tryOut = prefs_->GetCurrentStartupTryout();
  3205. + if (tryOut >= 3) {
  3206. + LOG(INFO) << "UserScriptLoader: Possible crash detected. UserScript disabled";
  3207. + prefs_->SetEnabled(false);
  3208. + } else {
  3209. + prefs_->StartupTryout(tryOut+1);
  3210. + StartLoad();
  3211. + }
  3212. +}
  3213. +
  3214. +void UserScriptLoader::StartLoad() {
  3215. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3216. +
  3217. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3218. + LOG(INFO) << "UserScriptLoader: StartLoad";
  3219. +
  3220. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  3221. + // the scripts aren't currently ready.
  3222. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  3223. + scripts_to_load->clear();
  3224. +
  3225. + if (prefs_->IsEnabled()) {
  3226. + LoadScripts(std::move(scripts_to_load),
  3227. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  3228. + weak_factory_.GetWeakPtr()));
  3229. + } else {
  3230. + OnScriptsLoaded(std::move(scripts_to_load));
  3231. + }
  3232. +}
  3233. +
  3234. +// static
  3235. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  3236. + const UserScriptList& scripts) {
  3237. + base::Pickle pickle;
  3238. + pickle.WriteUInt32(scripts.size());
  3239. + for (const std::unique_ptr<UserScript>& script : scripts) {
  3240. + // TODO(aa): This can be replaced by sending content script metadata to
  3241. + // renderers along with other extension data in ExtensionMsg_Loaded.
  3242. + // See crbug.com/70516.
  3243. + script->Pickle(&pickle);
  3244. + // Write scripts as 'data' so that we can read it out in the slave without
  3245. + // allocating a new string.
  3246. + for (const std::unique_ptr<UserScript::File>& js_file :
  3247. + script->js_scripts()) {
  3248. + base::StringPiece contents = js_file->GetContent();
  3249. + pickle.WriteData(contents.data(), contents.length());
  3250. + }
  3251. + for (const std::unique_ptr<UserScript::File>& css_file :
  3252. + script->css_scripts()) {
  3253. + base::StringPiece contents = css_file->GetContent();
  3254. + pickle.WriteData(contents.data(), contents.length());
  3255. + }
  3256. + }
  3257. +
  3258. + // Create the shared memory object.
  3259. + base::MappedReadOnlyRegion shared_memory =
  3260. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  3261. + if (!shared_memory.IsValid())
  3262. + return {};
  3263. +
  3264. + // Copy the pickle to shared memory.
  3265. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  3266. + return std::move(shared_memory.region);
  3267. +}
  3268. +
  3269. +void UserScriptLoader::AddObserver(Observer* observer) {
  3270. + observers_.AddObserver(observer);
  3271. +}
  3272. +
  3273. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  3274. + observers_.RemoveObserver(observer);
  3275. +}
  3276. +
  3277. +void UserScriptLoader::OnScriptsLoaded(
  3278. + std::unique_ptr<UserScriptList> user_scripts) {
  3279. +
  3280. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3281. + LOG(INFO) << "UserScriptLoader: OnScriptsLoaded";
  3282. +
  3283. + // Check user preferences for loaded user scripts
  3284. + prefs_->CompareWithPrefs(*user_scripts);
  3285. + loaded_scripts_ = std::move(user_scripts);
  3286. +
  3287. + base::ReadOnlySharedMemoryRegion shared_memory;
  3288. + shared_memory =
  3289. + UserScriptLoader::Serialize(*loaded_scripts_);
  3290. +
  3291. + if (!shared_memory.IsValid()) {
  3292. + // This can happen if we run out of file descriptors. In that case, we
  3293. + // have a choice between silently omitting all user scripts for new tabs,
  3294. + // by nulling out shared_memory_, or only silently omitting new ones by
  3295. + // leaving the existing object in place. The second seems less bad, even
  3296. + // though it removes the possibility that freeing the shared memory block
  3297. + // would open up enough FDs for long enough for a retry to succeed.
  3298. +
  3299. + // Pretend the extension change didn't happen.
  3300. + return;
  3301. + }
  3302. +
  3303. + // We've got scripts ready to go.
  3304. + shared_memory_ = std::move(shared_memory);
  3305. +
  3306. + for (content::RenderProcessHost::iterator i(
  3307. + content::RenderProcessHost::AllHostsIterator());
  3308. + !i.IsAtEnd(); i.Advance()) {
  3309. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  3310. + }
  3311. +
  3312. + // DCHECK(false); trying crash
  3313. + prefs_->StartupTryout(0);
  3314. +
  3315. + for (auto& observer : observers_)
  3316. + observer.OnScriptsLoaded(this, browser_context_);
  3317. +}
  3318. +
  3319. +void UserScriptLoader::SendUpdate(
  3320. + content::RenderProcessHost* process,
  3321. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  3322. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3323. + LOG(INFO) << "UserScriptLoader: SendUpdate";
  3324. +
  3325. + // If the process is being started asynchronously, early return. We'll end up
  3326. + // calling InitUserScripts when it's created which will call this again.
  3327. + base::ProcessHandle handle = process->GetProcess().Handle();
  3328. + if (!handle)
  3329. + return;
  3330. +
  3331. + base::ReadOnlySharedMemoryRegion region_for_process =
  3332. + shared_memory.Duplicate();
  3333. + if (!region_for_process.IsValid())
  3334. + return;
  3335. +
  3336. + process->Send(new ExtensionMsg_UpdateUserScripts(
  3337. + std::move(region_for_process)));
  3338. +}
  3339. +
  3340. +void LoadScriptsOnFileTaskRunner(
  3341. + std::unique_ptr<UserScriptList> user_scripts,
  3342. + UserScriptLoader::LoadScriptsCallback callback) {
  3343. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3344. + DCHECK(user_scripts.get());
  3345. +
  3346. + // load user scripts from path
  3347. + LoadUserScripts(user_scripts.get());
  3348. +
  3349. + // Explicit priority to prevent unwanted task priority inheritance.
  3350. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3351. + ->PostTask(FROM_HERE,
  3352. + base::BindOnce(std::move(callback), std::move(user_scripts)));
  3353. +}
  3354. +
  3355. +void UserScriptLoader::LoadScripts(
  3356. + std::unique_ptr<UserScriptList> user_scripts,
  3357. + LoadScriptsCallback callback) {
  3358. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  3359. +
  3360. + GetUserScriptsFileTaskRunner()->PostTask(
  3361. + FROM_HERE,
  3362. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  3363. + std::move(callback)));
  3364. +}
  3365. +
  3366. +void RemoveScriptsOnFileTaskRunner(
  3367. + const std::string& script_id,
  3368. + UserScriptLoader::RemoveScriptCallback callback) {
  3369. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3370. +
  3371. + base::FilePath path;
  3372. + if (GetOrCreatePath(path)) {
  3373. + base::FilePath file = path.Append(script_id);
  3374. + if (base::DeleteFile(file) == false) {
  3375. + LOG(ERROR) <<
  3376. + "ERROR: failed to delete file : " << path;
  3377. + }
  3378. + }
  3379. +
  3380. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3381. + ->PostTask(FROM_HERE,
  3382. + base::BindOnce(std::move(callback)));
  3383. +}
  3384. +
  3385. +void UserScriptLoader::OnScriptRemoved() {
  3386. + StartLoad();
  3387. +}
  3388. +
  3389. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  3390. + if (!prefs_->IsEnabled()) return;
  3391. + prefs_->RemoveScriptFromPrefs(script_id);
  3392. +
  3393. + GetUserScriptsFileTaskRunner()->PostTask(
  3394. + FROM_HERE,
  3395. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  3396. + std::move(script_id),
  3397. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  3398. + weak_factory_.GetWeakPtr())));
  3399. +}
  3400. +
  3401. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3402. + if (!prefs_->IsEnabled()) return;
  3403. + prefs_->SetScriptEnabled(script_id, is_enabled);
  3404. + StartLoad();
  3405. +}
  3406. +
  3407. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  3408. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3409. +
  3410. + if (!prefs_->IsEnabled()) return;
  3411. +
  3412. + dialog_ = ui::SelectFileDialog::Create(
  3413. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  3414. +
  3415. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  3416. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  3417. + allowed_file_info.allowed_paths =
  3418. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  3419. + base::FilePath suggested_name;
  3420. +
  3421. + std::vector<std::u16string> types;
  3422. + types.push_back(u"*/*"); /*= java SelectFileDialog.ALL_TYPES*/
  3423. + std::pair<std::vector<std::u16string>, bool> accept_types = std::make_pair(
  3424. + types, false /*use_media_capture*/);
  3425. +
  3426. + dialog_->SelectFile(
  3427. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  3428. + std::u16string() /* dialog title*/, suggested_name, &allowed_file_info,
  3429. + 0 /* file type index */, std::string() /* default file extension */,
  3430. + nativeWindow,
  3431. + &accept_types /* params */);
  3432. +}
  3433. +
  3434. +
  3435. +void LoadScriptFromPathOnFileTaskRunner(
  3436. + const base::FilePath& path,
  3437. + const std::string& display_name,
  3438. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  3439. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3440. +
  3441. + std::unique_ptr<UserScript> userscript(new UserScript());
  3442. + std::u16string error;
  3443. + bool found_metadata = false;
  3444. + bool loaded = LoadUserScriptFromFile(path, GURL(), userscript, &found_metadata, &error);
  3445. +
  3446. + bool result = loaded;
  3447. + if (result || found_metadata) {
  3448. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3449. + LOG(INFO) << "UserScriptLoader: found " << userscript->name() <<
  3450. + "-" << userscript->version() <<
  3451. + "-" << userscript->description();
  3452. + base::FilePath destination;
  3453. + if (GetOrCreatePath(destination) == false) {
  3454. + error = u"Cannot create destination.";
  3455. + } else {
  3456. + // we need an unique file name
  3457. + if (display_name.empty() == false) {
  3458. + userscript->set_key(display_name);
  3459. + }
  3460. +
  3461. + // filename is original filename or display_name
  3462. + std::string file_name(userscript->key());
  3463. + base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
  3464. + destination = destination.Append(file_name);
  3465. +
  3466. + if (destination.ReferencesParent()) {
  3467. + error = u"Invalid file name.";
  3468. + result = false;
  3469. + } else if (base::PathExists(destination)) {
  3470. + error = u"User script already loaded.";
  3471. + result = false;
  3472. + } else {
  3473. + if (loaded) {
  3474. + // if is a correct userscript, copy it
  3475. + result = base::CopyFile(path, destination);
  3476. + if (result == false) {
  3477. + error = u"Copy error.";
  3478. + }
  3479. + } else {
  3480. + // else, there is a parser error
  3481. + // write minimal values and the error string, so UI can show it
  3482. + std::string combined_string = base::StrCat({
  3483. + kUserScriptBegin, "\n",
  3484. + kNamespaceDeclaration, " ", userscript->name_space(), "\n",
  3485. + kNameDeclaration, " ", userscript->name(), "\n",
  3486. + kVersionDeclaration, " ", userscript->version(), "\n",
  3487. + kDescriptionDeclaration, " ", userscript->description(), "\n",
  3488. + kUrlSourceDeclaration, " ", userscript->url_source(), "\n",
  3489. + kParserError, " ", base::UTF16ToASCII(error), "\n",
  3490. + kForceDisabled, " true\n",
  3491. + kUserScriptEnd, "\n"
  3492. + });
  3493. +
  3494. + if (!base::WriteFile(destination, combined_string)) {
  3495. + error = u"Cannot write.";
  3496. + result = false;
  3497. + }
  3498. + }
  3499. + }
  3500. + }
  3501. + }
  3502. +
  3503. + if (!error.empty()) {
  3504. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3505. + }
  3506. +
  3507. + // return to callback with eventually the error
  3508. + const std::string string_error = base::UTF16ToASCII(error);
  3509. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3510. + ->PostTask(FROM_HERE,
  3511. + base::BindOnce(std::move(callback), result,
  3512. + std::move(string_error)));
  3513. +}
  3514. +
  3515. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  3516. + if (!prefs_->IsEnabled()) return;
  3517. +
  3518. + std::u16string file_display_name;
  3519. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  3520. +
  3521. + std::string display_name = script_path.BaseName().value();
  3522. + if (base::IsStringASCII(file_display_name))
  3523. + display_name = base::UTF16ToASCII(file_display_name);
  3524. +
  3525. + GetUserScriptsFileTaskRunner()->PostTask(
  3526. + FROM_HERE,
  3527. + base::BindOnce(
  3528. + &LoadScriptFromPathOnFileTaskRunner,
  3529. + script_path, display_name,
  3530. + base::BindOnce(
  3531. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  3532. + weak_factory_.GetWeakPtr()
  3533. + )
  3534. + ));
  3535. +}
  3536. +
  3537. +void UserScriptLoader::FileSelected(
  3538. + const base::FilePath& path, int index, void* params) {
  3539. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3540. + LOG(INFO) << "UserScriptLoader: FileSelected " << path;
  3541. +
  3542. + UserScriptLoader::TryToInstall(path);
  3543. +}
  3544. +
  3545. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  3546. + bool result, const std::string& error) {
  3547. + for (auto& observer : observers_)
  3548. + observer.OnUserScriptLoaded(this, result, error);
  3549. +
  3550. + StartLoad();
  3551. +}
  3552. +
  3553. +void UserScriptLoader::FileSelectionCanceled(
  3554. + void* params) {
  3555. +}
  3556. +
  3557. +} // namespace extensions
  3558. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  3559. new file mode 100755
  3560. --- /dev/null
  3561. +++ b/components/user_scripts/browser/user_script_loader.h
  3562. @@ -0,0 +1,169 @@
  3563. +/*
  3564. + This file is part of Bromite.
  3565. +
  3566. + Bromite is free software: you can redistribute it and/or modify
  3567. + it under the terms of the GNU General Public License as published by
  3568. + the Free Software Foundation, either version 3 of the License, or
  3569. + (at your option) any later version.
  3570. +
  3571. + Bromite is distributed in the hope that it will be useful,
  3572. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3573. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3574. + GNU General Public License for more details.
  3575. +
  3576. + You should have received a copy of the GNU General Public License
  3577. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3578. +*/
  3579. +
  3580. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3581. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3582. +
  3583. +#include <map>
  3584. +#include <memory>
  3585. +#include <set>
  3586. +
  3587. +#include "base/callback_forward.h"
  3588. +#include "base/compiler_specific.h"
  3589. +#include "base/memory/read_only_shared_memory_region.h"
  3590. +#include "base/memory/weak_ptr.h"
  3591. +#include "base/observer_list.h"
  3592. +#include "content/public/browser/render_process_host_creation_observer.h"
  3593. +#include "ui/shell_dialogs/select_file_dialog.h"
  3594. +#include "content/browser/file_system_access/file_system_chooser.h"
  3595. +#include "ui/android/window_android.h"
  3596. +
  3597. +#include "../common/host_id.h"
  3598. +#include "../common/user_script.h"
  3599. +#include "user_script_prefs.h"
  3600. +
  3601. +namespace base {
  3602. +class ReadOnlySharedMemoryRegion;
  3603. +}
  3604. +
  3605. +namespace content {
  3606. +class BrowserContext;
  3607. +class RenderProcessHost;
  3608. +}
  3609. +
  3610. +namespace user_scripts {
  3611. +
  3612. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  3613. +// new shared memory region when the set of scripts changes. Also notifies
  3614. +// renderers of new shared memory region when new renderers appear, or when
  3615. +// script reloading completes. Script loading lives on the file thread.
  3616. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  3617. + public ui::SelectFileDialog::Listener {
  3618. + public:
  3619. + UserScriptLoader(const UserScriptLoader&) = delete;
  3620. + UserScriptLoader& operator=(const UserScriptLoader&) = delete;
  3621. + using LoadScriptsCallback =
  3622. + base::OnceCallback<void(std::unique_ptr<UserScriptList>)>;
  3623. + using LoadSingleScriptCallback =
  3624. + base::OnceCallback<void(bool result, const std::string& error)>;
  3625. +
  3626. + using RemoveScriptCallback =
  3627. + base::OnceCallback<void()>;
  3628. + class Observer {
  3629. + public:
  3630. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  3631. + content::BrowserContext* browser_context) = 0;
  3632. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  3633. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  3634. + bool result, const std::string& error) = 0;
  3635. + };
  3636. +
  3637. + // Parses the includes out of |script| and returns them in |includes|.
  3638. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  3639. + std::unique_ptr<UserScript>& script,
  3640. + bool *found_metadata,
  3641. + std::string& error_message);
  3642. +
  3643. + UserScriptLoader(content::BrowserContext* browser_context,
  3644. + UserScriptsPrefs* prefs);
  3645. + //const HostID& host_id);
  3646. + ~UserScriptLoader() override;
  3647. +
  3648. + // Initiates procedure to start loading scripts on the file thread.
  3649. + void StartLoad();
  3650. +
  3651. + // Returns true if we have any scripts ready.
  3652. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  3653. +
  3654. + // Pickle user scripts and return pointer to the shared memory.
  3655. + static base::ReadOnlySharedMemoryRegion Serialize(
  3656. + const user_scripts::UserScriptList& scripts);
  3657. +
  3658. + // Adds or removes observers.
  3659. + void AddObserver(Observer* observer);
  3660. + void RemoveObserver(Observer* observer);
  3661. +
  3662. + // Sets the flag if the initial set of hosts has finished loading; if it's
  3663. + // set to be true, calls AttempLoad() to bootstrap.
  3664. + void SetReady(bool ready);
  3665. +
  3666. + void RemoveScript(const std::string& script_id);
  3667. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3668. +
  3669. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  3670. + void TryToInstall(const base::FilePath& script_path);
  3671. +
  3672. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  3673. + LoadScriptsCallback callback);
  3674. +
  3675. + protected:
  3676. + content::BrowserContext* browser_context() const { return browser_context_; }
  3677. +
  3678. + UserScriptsPrefs* prefs() const { return prefs_; }
  3679. +
  3680. + private:
  3681. + void OnRenderProcessHostCreated(
  3682. + content::RenderProcessHost* process_host) override;
  3683. +
  3684. + // Attempts to initiate a load.
  3685. + void AttemptLoad();
  3686. +
  3687. + // Called once we have finished loading the scripts on the file thread.
  3688. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts);
  3689. +
  3690. + // Sends the renderer process a new set of user scripts. If
  3691. + // |changed_hosts| is not empty, this signals that only the scripts from
  3692. + // those hosts should be updated. Otherwise, all hosts will be
  3693. + // updated.
  3694. + void SendUpdate(content::RenderProcessHost* process,
  3695. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  3696. +
  3697. + // Contains the scripts that were found the last time scripts were updated.
  3698. + base::ReadOnlySharedMemoryRegion shared_memory_;
  3699. +
  3700. + // List of scripts that are currently loaded. This is null when a load is in
  3701. + // progress.
  3702. + std::unique_ptr<UserScriptList> loaded_scripts_;
  3703. +
  3704. + // If the initial set of hosts has finished loading.
  3705. + bool ready_;
  3706. +
  3707. + // The browser_context for which the scripts managed here are installed.
  3708. + content::BrowserContext* browser_context_;
  3709. +
  3710. + // Manage load and store from preferences
  3711. + UserScriptsPrefs* prefs_;
  3712. +
  3713. + // The associated observers.
  3714. + base::ObserverList<Observer>::Unchecked observers_;
  3715. +
  3716. + void OnScriptRemoved();
  3717. +
  3718. + // Manage file dialog requests
  3719. + scoped_refptr<ui::SelectFileDialog> dialog_;
  3720. + void FileSelected(const base::FilePath& path,
  3721. + int index, void* params) override;
  3722. + void FileSelectionCanceled(void* params) override;
  3723. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  3724. + bool result, const std::string& error );
  3725. +
  3726. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  3727. +};
  3728. +
  3729. +} // namespace extensions
  3730. +
  3731. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3732. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  3733. new file mode 100644
  3734. --- /dev/null
  3735. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  3736. @@ -0,0 +1,34 @@
  3737. +/*
  3738. + This file is part of Bromite.
  3739. +
  3740. + Bromite is free software: you can redistribute it and/or modify
  3741. + it under the terms of the GNU General Public License as published by
  3742. + the Free Software Foundation, either version 3 of the License, or
  3743. + (at your option) any later version.
  3744. +
  3745. + Bromite is distributed in the hope that it will be useful,
  3746. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3747. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3748. + GNU General Public License for more details.
  3749. +
  3750. + You should have received a copy of the GNU General Public License
  3751. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3752. +*/
  3753. +
  3754. +#include "user_script_pref_info.h"
  3755. +
  3756. +namespace user_scripts {
  3757. +
  3758. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  3759. + const std::string& description,
  3760. + const base::Time& install_time,
  3761. + bool enabled)
  3762. + : install_time(install_time),
  3763. + enabled(enabled),
  3764. + name_(name),
  3765. + description_(description) {}
  3766. +
  3767. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  3768. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  3769. +
  3770. +}
  3771. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3772. new file mode 100644
  3773. --- /dev/null
  3774. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3775. @@ -0,0 +1,72 @@
  3776. +/*
  3777. + This file is part of Bromite.
  3778. +
  3779. + Bromite is free software: you can redistribute it and/or modify
  3780. + it under the terms of the GNU General Public License as published by
  3781. + the Free Software Foundation, either version 3 of the License, or
  3782. + (at your option) any later version.
  3783. +
  3784. + Bromite is distributed in the hope that it will be useful,
  3785. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3786. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3787. + GNU General Public License for more details.
  3788. +
  3789. + You should have received a copy of the GNU General Public License
  3790. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3791. +*/
  3792. +
  3793. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3794. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3795. +
  3796. +#include "base/values.h"
  3797. +#include "base/time/time.h"
  3798. +#include "components/keyed_service/core/keyed_service.h"
  3799. +
  3800. +namespace user_scripts {
  3801. +
  3802. +class UserScriptsListPrefs : public KeyedService {
  3803. + public:
  3804. + struct ScriptInfo {
  3805. + ScriptInfo(const std::string& name,
  3806. + const std::string& description,
  3807. + const base::Time& install_time,
  3808. + bool enabled);
  3809. + ScriptInfo(const ScriptInfo& other);
  3810. + ~ScriptInfo();
  3811. +
  3812. + const std::string& name() const { return name_; }
  3813. + void set_name(const std::string& name) { name_ = name; }
  3814. +
  3815. + const std::string& description() const { return description_; }
  3816. + void set_description(const std::string& description) { description_ = description; }
  3817. +
  3818. + const std::string& version() const { return version_; }
  3819. + void set_version(const std::string& version) { version_ = version; }
  3820. +
  3821. + const std::string& file_path() const { return file_path_; }
  3822. + void set_file_path(const std::string& file_path) { file_path_ = file_path; }
  3823. +
  3824. + const std::string& url_source() const { return url_source_; }
  3825. + void set_url_source(const std::string& url_source) { url_source_ = url_source; }
  3826. +
  3827. + const std::string& parser_error() const { return parser_error_; }
  3828. + void set_parser_error(const std::string& parser_error) { parser_error_ = parser_error; }
  3829. +
  3830. + base::Time install_time;
  3831. + bool enabled;
  3832. +
  3833. + bool force_disabled;
  3834. +
  3835. + private:
  3836. + std::string name_;
  3837. + std::string description_;
  3838. + std::string version_;
  3839. + std::string file_path_;
  3840. + std::string url_source_;
  3841. + std::string parser_error_;
  3842. + };
  3843. +};
  3844. +
  3845. +}
  3846. +
  3847. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3848. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3849. new file mode 100644
  3850. --- /dev/null
  3851. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3852. @@ -0,0 +1,278 @@
  3853. +/*
  3854. + This file is part of Bromite.
  3855. +
  3856. + Bromite is free software: you can redistribute it and/or modify
  3857. + it under the terms of the GNU General Public License as published by
  3858. + the Free Software Foundation, either version 3 of the License, or
  3859. + (at your option) any later version.
  3860. +
  3861. + Bromite is distributed in the hope that it will be useful,
  3862. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3863. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3864. + GNU General Public License for more details.
  3865. +
  3866. + You should have received a copy of the GNU General Public License
  3867. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3868. +*/
  3869. +
  3870. +#include <map>
  3871. +
  3872. +#include "base/values.h"
  3873. +#include "base/strings/string_number_conversions.h"
  3874. +#include "base/json/json_writer.h"
  3875. +
  3876. +#include "chrome/browser/browser_process.h"
  3877. +#include "chrome/browser/profiles/profile.h"
  3878. +#include "chrome/browser/profiles/profile_manager.h"
  3879. +
  3880. +#include "components/prefs/pref_registry_simple.h"
  3881. +#include "components/prefs/pref_service.h"
  3882. +#include "components/prefs/scoped_user_pref_update.h"
  3883. +#include "components/pref_registry/pref_registry_syncable.h"
  3884. +#include "user_script_prefs.h"
  3885. +#include "user_script_pref_info.h"
  3886. +#include "../common/user_script.h"
  3887. +#include "../common/user_scripts_features.h"
  3888. +
  3889. +namespace user_scripts {
  3890. +
  3891. +namespace prefs {
  3892. + const char kUserScriptsEnabled[] = "userscripts.enabled";
  3893. +}
  3894. +
  3895. +namespace {
  3896. +
  3897. +const char kUserScriptsStartup[] = "userscripts.startup";
  3898. +
  3899. +const char kUserScriptsList[] = "userscripts.scripts";
  3900. +const char kScriptIsEnabled[] = "enabled";
  3901. +const char kScriptName[] = "name";
  3902. +const char kScriptDescription[] = "description";
  3903. +const char kScriptVersion[] = "version";
  3904. +const char kScriptInstallTime[] = "install_time";
  3905. +const char kScriptFilePath[] = "file_path";
  3906. +const char kScriptUrlSource[] = "url_source";
  3907. +const char kScriptParserError[] = "parser_error";
  3908. +const char kScriptForceDisabled[] = "force_disabled";
  3909. +
  3910. +class PrefUpdate : public DictionaryPrefUpdate {
  3911. + public:
  3912. + PrefUpdate(PrefService* service,
  3913. + const std::string& id,
  3914. + const std::string& path)
  3915. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3916. +
  3917. + PrefUpdate(const PrefUpdate&) = delete;
  3918. + PrefUpdate& operator=(const PrefUpdate&) = delete;
  3919. + ~PrefUpdate() override = default;
  3920. +
  3921. + base::Value* Get() override {
  3922. + base::Value* dict = DictionaryPrefUpdate::Get();
  3923. + base::Value* dict_item =
  3924. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3925. + if (!dict_item)
  3926. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3927. + return dict_item;
  3928. + }
  3929. +
  3930. + private:
  3931. + const std::string id_;
  3932. +};
  3933. +
  3934. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3935. + const std::string& key,
  3936. + int64_t* value) {
  3937. + DCHECK(dict);
  3938. + const std::string* value_str = dict->FindStringKey(key);
  3939. + if (!value_str) {
  3940. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3941. + << ".";
  3942. + return false;
  3943. + }
  3944. +
  3945. + if (!base::StringToInt64(*value_str, value)) {
  3946. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3947. + << *value_str << ".";
  3948. + return false;
  3949. + }
  3950. +
  3951. + return true;
  3952. +}
  3953. +
  3954. +}
  3955. +
  3956. +UserScriptsPrefs::UserScriptsPrefs(
  3957. + PrefService* prefs)
  3958. + : prefs_(prefs) {
  3959. +}
  3960. +
  3961. +// static
  3962. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3963. + registry->RegisterBooleanPref(prefs::kUserScriptsEnabled, false);
  3964. + registry->RegisterIntegerPref(kUserScriptsStartup, 0);
  3965. + registry->RegisterDictionaryPref(kUserScriptsList);
  3966. +}
  3967. +
  3968. +bool UserScriptsPrefs::IsEnabled() {
  3969. + return prefs_->GetBoolean(prefs::kUserScriptsEnabled);
  3970. +}
  3971. +
  3972. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3973. + prefs_->SetBoolean(prefs::kUserScriptsEnabled, enabled);
  3974. + prefs_->CommitPendingWrite();
  3975. +}
  3976. +
  3977. +void UserScriptsPrefs::StartupTryout(int number) {
  3978. + prefs_->SetInteger(kUserScriptsStartup, number);
  3979. + prefs_->CommitPendingWrite();
  3980. +}
  3981. +
  3982. +int UserScriptsPrefs::GetCurrentStartupTryout() {
  3983. + return prefs_->GetInteger(kUserScriptsStartup);
  3984. +}
  3985. +
  3986. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3987. + if (IsEnabled() == false) {
  3988. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3989. + LOG(INFO) << "UserScriptsPrefs: disabled by user";
  3990. +
  3991. + user_scripts.clear();
  3992. + return;
  3993. + }
  3994. +
  3995. + std::vector<std::string> all_scripts;
  3996. +
  3997. + auto it = user_scripts.begin();
  3998. + while (it != user_scripts.end())
  3999. + {
  4000. + std::string key = it->get()->key();
  4001. + all_scripts.push_back(key);
  4002. +
  4003. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  4004. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  4005. +
  4006. + // add or update prefs
  4007. + scriptInfo->set_name(it->get()->name());
  4008. + scriptInfo->set_description(it->get()->description());
  4009. + scriptInfo->set_version(it->get()->version());
  4010. + scriptInfo->set_file_path(it->get()->file_path());
  4011. + scriptInfo->set_url_source(it->get()->url_source());
  4012. + scriptInfo->set_parser_error(it->get()->parser_error());
  4013. + scriptInfo->force_disabled = (it->get()->force_disabled());
  4014. +
  4015. + PrefUpdate update(prefs_, key, kUserScriptsList);
  4016. + base::Value* script_dict = update.Get();
  4017. +
  4018. + script_dict->SetStringKey(kScriptName, scriptInfo->name());
  4019. + script_dict->SetStringKey(kScriptDescription, scriptInfo->description());
  4020. + script_dict->SetBoolKey(kScriptIsEnabled, scriptInfo->enabled);
  4021. + script_dict->SetStringKey(kScriptVersion, scriptInfo->version());
  4022. + script_dict->SetStringKey(kScriptFilePath, scriptInfo->file_path());
  4023. + script_dict->SetStringKey(kScriptUrlSource, scriptInfo->url_source());
  4024. + script_dict->SetStringKey(kScriptParserError, scriptInfo->parser_error());
  4025. + script_dict->SetBoolKey(kScriptForceDisabled, scriptInfo->force_disabled);
  4026. +
  4027. + std::string install_time_str =
  4028. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  4029. + script_dict->SetStringKey(kScriptInstallTime, install_time_str);
  4030. +
  4031. + if (!scriptInfo->enabled) {
  4032. + it = user_scripts.erase(it);
  4033. + } else {
  4034. + ++it;
  4035. + }
  4036. + }
  4037. +
  4038. + // remove script from prefs if no more present
  4039. + std::vector<std::string> all_scripts_to_remove;
  4040. + const base::DictionaryValue* dict =
  4041. + &base::Value::AsDictionaryValue(*prefs_->GetDictionary(
  4042. + kUserScriptsList));
  4043. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  4044. + script_it.Advance()) {
  4045. + const std::string& key = script_it.key();
  4046. +
  4047. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  4048. + all_scripts_to_remove.push_back(key);
  4049. + }
  4050. + }
  4051. +
  4052. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4053. + base::Value* const update_dict = update.Get();
  4054. + for (auto key : all_scripts_to_remove) {
  4055. + update_dict->RemoveKey(key);
  4056. + }
  4057. +
  4058. + return;
  4059. +}
  4060. +
  4061. +std::string UserScriptsPrefs::GetScriptsInfo() {
  4062. + std::string json_string;
  4063. +
  4064. + const base::Value* dict =
  4065. + prefs_->GetDictionary(kUserScriptsList);
  4066. +
  4067. + if (dict) {
  4068. + base::JSONWriter::WriteWithOptions(
  4069. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  4070. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  4071. + }
  4072. +
  4073. + return json_string;
  4074. +}
  4075. +
  4076. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  4077. + const std::string& script_id) const {
  4078. +
  4079. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  4080. + script_id, "", base::Time::Now(), false);
  4081. +
  4082. + const base::Value* scripts =
  4083. + prefs_->GetDictionary(kUserScriptsList);
  4084. + if (!scripts)
  4085. + return scriptInfo;
  4086. +
  4087. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  4088. + scripts->FindDictKey(script_id));
  4089. + if (!script)
  4090. + return scriptInfo;
  4091. +
  4092. + const std::string* name = script->FindStringKey(kScriptName);
  4093. + const std::string* description = script->FindStringKey(kScriptDescription);
  4094. + const std::string* version = script->FindStringKey(kScriptVersion);
  4095. + const std::string* file_path = script->FindStringKey(kScriptFilePath);
  4096. + const std::string* url_source = script->FindStringKey(kScriptUrlSource);
  4097. + const std::string* parser_error = script->FindStringKey(kScriptParserError);
  4098. +
  4099. + scriptInfo->set_name( name ? *name : "no name" );
  4100. + scriptInfo->set_description( description ? *description : "no description" );
  4101. + scriptInfo->set_version( version ? *version : "no version" );
  4102. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  4103. + scriptInfo->set_file_path( file_path ? *file_path : "no file path" );
  4104. + scriptInfo->set_url_source( url_source ? *url_source : "" );
  4105. + scriptInfo->set_parser_error( parser_error ? *parser_error : "" );
  4106. + scriptInfo->force_disabled = script->FindBoolKey(kScriptForceDisabled).value_or(false);
  4107. +
  4108. + int64_t time_interval = 0;
  4109. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  4110. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  4111. + }
  4112. +
  4113. + return scriptInfo;
  4114. +}
  4115. +
  4116. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  4117. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4118. + base::Value* const update_dict = update.Get();
  4119. + update_dict->RemoveKey(script_id);
  4120. +}
  4121. +
  4122. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  4123. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  4124. + base::Value* script_dict = update.Get();
  4125. + if (script_dict->FindBoolKey(kScriptForceDisabled).value_or(false))
  4126. + is_enabled = true;
  4127. + script_dict->SetBoolKey(kScriptIsEnabled, is_enabled);
  4128. +}
  4129. +
  4130. +}
  4131. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  4132. new file mode 100644
  4133. --- /dev/null
  4134. +++ b/components/user_scripts/browser/user_script_prefs.h
  4135. @@ -0,0 +1,62 @@
  4136. +/*
  4137. + This file is part of Bromite.
  4138. +
  4139. + Bromite is free software: you can redistribute it and/or modify
  4140. + it under the terms of the GNU General Public License as published by
  4141. + the Free Software Foundation, either version 3 of the License, or
  4142. + (at your option) any later version.
  4143. +
  4144. + Bromite is distributed in the hope that it will be useful,
  4145. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4146. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4147. + GNU General Public License for more details.
  4148. +
  4149. + You should have received a copy of the GNU General Public License
  4150. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4151. +*/
  4152. +
  4153. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4154. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4155. +
  4156. +#include "content/public/browser/browser_context.h"
  4157. +#include "components/prefs/pref_service.h"
  4158. +#include "components/pref_registry/pref_registry_syncable.h"
  4159. +
  4160. +#include "user_script_pref_info.h"
  4161. +#include "../common/user_script.h"
  4162. +
  4163. +namespace user_scripts {
  4164. +
  4165. +namespace prefs {
  4166. + extern const char kUserScriptsEnabled[];
  4167. +}
  4168. +
  4169. +class UserScriptsPrefs {
  4170. + public:
  4171. + UserScriptsPrefs(
  4172. + PrefService* prefs);
  4173. +
  4174. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  4175. +
  4176. + bool IsEnabled();
  4177. + void SetEnabled(bool enabled);
  4178. +
  4179. + void StartupTryout(int number);
  4180. + int GetCurrentStartupTryout();
  4181. +
  4182. + void CompareWithPrefs(UserScriptList& user_scripts);
  4183. +
  4184. + std::string GetScriptsInfo();
  4185. + void RemoveScriptFromPrefs(const std::string& script_id);
  4186. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  4187. +
  4188. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  4189. + const std::string& script_id) const;
  4190. +
  4191. + private:
  4192. + PrefService* prefs_;
  4193. +};
  4194. +
  4195. +}
  4196. +
  4197. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4198. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  4199. new file mode 100755
  4200. --- /dev/null
  4201. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  4202. @@ -0,0 +1,78 @@
  4203. +/*
  4204. + This file is part of Bromite.
  4205. +
  4206. + Bromite is free software: you can redistribute it and/or modify
  4207. + it under the terms of the GNU General Public License as published by
  4208. + the Free Software Foundation, either version 3 of the License, or
  4209. + (at your option) any later version.
  4210. +
  4211. + Bromite is distributed in the hope that it will be useful,
  4212. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4213. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4214. + GNU General Public License for more details.
  4215. +
  4216. + You should have received a copy of the GNU General Public License
  4217. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4218. +*/
  4219. +
  4220. +#include "userscripts_browser_client.h"
  4221. +
  4222. +#include "base/logging.h"
  4223. +
  4224. +#include "chrome/browser/browser_process.h"
  4225. +
  4226. +#include "chrome/browser/profiles/profile.h"
  4227. +#include "chrome/browser/profiles/profile_manager.h"
  4228. +
  4229. +#include "../common/user_scripts_features.h"
  4230. +#include "user_script_loader.h"
  4231. +#include "file_task_runner.h"
  4232. +#include "user_script_prefs.h"
  4233. +
  4234. +namespace user_scripts {
  4235. +
  4236. +namespace {
  4237. +
  4238. +// remember: was ExtensionsBrowserClient
  4239. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  4240. +
  4241. +} // namespace
  4242. +
  4243. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  4244. +
  4245. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  4246. +
  4247. +// static
  4248. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  4249. + // only for browser process
  4250. + if (!g_browser_process)
  4251. + return NULL;
  4252. +
  4253. + // singleton
  4254. + if (g_userscripts_browser_client)
  4255. + return g_userscripts_browser_client;
  4256. +
  4257. + // make file task runner
  4258. + GetUserScriptsFileTaskRunner().get();
  4259. +
  4260. + // new instance singleton
  4261. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  4262. +
  4263. + return g_userscripts_browser_client;
  4264. +}
  4265. +
  4266. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  4267. + browser_context_ = context;
  4268. +
  4269. + prefs_ =
  4270. + std::make_unique<user_scripts::UserScriptsPrefs>(
  4271. + static_cast<Profile*>(context)->GetPrefs());
  4272. +
  4273. + userscript_loader_ =
  4274. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  4275. + if (prefs_->IsEnabled()) {
  4276. + userscript_loader_->SetReady(true);
  4277. + }
  4278. +}
  4279. +
  4280. +} // namespace user_scripts
  4281. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  4282. new file mode 100755
  4283. --- /dev/null
  4284. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  4285. @@ -0,0 +1,62 @@
  4286. +/*
  4287. + This file is part of Bromite.
  4288. +
  4289. + Bromite is free software: you can redistribute it and/or modify
  4290. + it under the terms of the GNU General Public License as published by
  4291. + the Free Software Foundation, either version 3 of the License, or
  4292. + (at your option) any later version.
  4293. +
  4294. + Bromite is distributed in the hope that it will be useful,
  4295. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4296. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4297. + GNU General Public License for more details.
  4298. +
  4299. + You should have received a copy of the GNU General Public License
  4300. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4301. +*/
  4302. +
  4303. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4304. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4305. +
  4306. +#include <memory>
  4307. +#include <string>
  4308. +#include <vector>
  4309. +
  4310. +#include "content/public/browser/browser_context.h"
  4311. +
  4312. +#include "../common/user_script.h"
  4313. +#include "user_script_loader.h"
  4314. +#include "user_script_prefs.h"
  4315. +
  4316. +namespace user_scripts {
  4317. +
  4318. +class UserScriptsBrowserClient {
  4319. + public:
  4320. + UserScriptsBrowserClient();
  4321. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  4322. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  4323. + virtual ~UserScriptsBrowserClient();
  4324. +
  4325. + // Returns the single instance of |this|.
  4326. + static UserScriptsBrowserClient* GetInstance();
  4327. +
  4328. + void SetProfile(content::BrowserContext* context);
  4329. +
  4330. + user_scripts::UserScriptsPrefs* GetPrefs() {
  4331. + return prefs_.get();
  4332. + }
  4333. +
  4334. + user_scripts::UserScriptLoader* GetLoader() {
  4335. + return userscript_loader_.get();
  4336. + }
  4337. +
  4338. + private:
  4339. + std::unique_ptr<UserScriptList> scripts_;
  4340. + content::BrowserContext* browser_context_;
  4341. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  4342. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  4343. +};
  4344. +
  4345. +} // namespace extensions
  4346. +
  4347. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4348. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  4349. new file mode 100755
  4350. --- /dev/null
  4351. +++ b/components/user_scripts/common/BUILD.gn
  4352. @@ -0,0 +1,49 @@
  4353. +# Copyright 2014 The Chromium Authors. All rights reserved.
  4354. +# Use of this source code is governed by a BSD-style license that can be
  4355. +# found in the LICENSE file.
  4356. +
  4357. +import("//build/config/features.gni")
  4358. +import("//mojo/public/tools/bindings/mojom.gni")
  4359. +
  4360. +static_library("common") {
  4361. + sources = [
  4362. + "user_scripts_features.cc",
  4363. + "user_scripts_features.h",
  4364. + "constants.h",
  4365. + "host_id.cc",
  4366. + "host_id.h",
  4367. + "script_constants.h",
  4368. + "url_pattern_set.cc",
  4369. + "url_pattern_set.h",
  4370. + "url_pattern.cc",
  4371. + "url_pattern.h",
  4372. + "user_script.cc",
  4373. + "user_script.h",
  4374. + "view_type.cc",
  4375. + "view_type.h",
  4376. + "extension_messages.cc",
  4377. + "extension_messages.h",
  4378. + "extension_message_generator.cc",
  4379. + "extension_message_generator.h",
  4380. + ]
  4381. +
  4382. + configs += [
  4383. + "//build/config:precompiled_headers",
  4384. + "//build/config/compiler:wexit_time_destructors",
  4385. + ]
  4386. +
  4387. + public_deps = [
  4388. + "//components/services/app_service/public/cpp:app_file_handling",
  4389. + "//content/public/common",
  4390. + "//ipc",
  4391. + "//skia",
  4392. + ]
  4393. +
  4394. + deps = [
  4395. + "//base",
  4396. + "//components/url_formatter",
  4397. + "//components/url_matcher",
  4398. + "//components/version_info",
  4399. + "//crypto",
  4400. + ]
  4401. +}
  4402. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  4403. new file mode 100755
  4404. --- /dev/null
  4405. +++ b/components/user_scripts/common/constants.h
  4406. @@ -0,0 +1,21 @@
  4407. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4408. +// Use of this source code is governed by a BSD-style license that can be
  4409. +// found in the LICENSE file.
  4410. +
  4411. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  4412. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  4413. +
  4414. +#include "base/files/file_path.h"
  4415. +#include "base/strings/string_piece_forward.h"
  4416. +#include "components/services/app_service/public/mojom/types.mojom.h"
  4417. +#include "components/version_info/channel.h"
  4418. +#include "ui/base/layout.h"
  4419. +
  4420. +namespace user_scripts {
  4421. +
  4422. +// The origin of injected CSS.
  4423. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  4424. +
  4425. +} // namespace user_scripts
  4426. +
  4427. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  4428. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  4429. new file mode 100755
  4430. --- /dev/null
  4431. +++ b/components/user_scripts/common/error_utils.cc
  4432. @@ -0,0 +1,54 @@
  4433. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4434. +// Use of this source code is governed by a BSD-style license that can be
  4435. +// found in the LICENSE file.
  4436. +
  4437. +#include "error_utils.h"
  4438. +
  4439. +#include <initializer_list>
  4440. +
  4441. +#include "base/check_op.h"
  4442. +#include "base/strings/string_tokenizer.h"
  4443. +#include "base/strings/string_util.h"
  4444. +#include "base/strings/utf_string_conversions.h"
  4445. +
  4446. +namespace user_scripts {
  4447. +
  4448. +namespace {
  4449. +
  4450. +std::string FormatErrorMessageInternal(
  4451. + base::StringPiece format,
  4452. + std::initializer_list<base::StringPiece> args) {
  4453. + std::string format_str = format.as_string();
  4454. + base::StringTokenizer tokenizer(format_str, "*");
  4455. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  4456. +
  4457. + std::vector<base::StringPiece> result_pieces;
  4458. + auto* args_it = args.begin();
  4459. + while (tokenizer.GetNext()) {
  4460. + if (!tokenizer.token_is_delim()) {
  4461. + result_pieces.push_back(tokenizer.token_piece());
  4462. + continue;
  4463. + }
  4464. +
  4465. + CHECK_NE(args_it, args.end())
  4466. + << "More placeholders (*) than substitutions.";
  4467. +
  4468. + // Substitute the argument.
  4469. + result_pieces.push_back(*args_it);
  4470. + args_it++;
  4471. + }
  4472. +
  4473. + // Not all substitutions were consumed.
  4474. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  4475. +
  4476. + return base::JoinString(result_pieces, "" /* separator */);
  4477. +}
  4478. +
  4479. +} // namespace
  4480. +
  4481. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  4482. + base::StringPiece s1) {
  4483. + return FormatErrorMessageInternal(format, {s1});
  4484. +}
  4485. +
  4486. +} // namespace user_scripts
  4487. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  4488. new file mode 100755
  4489. --- /dev/null
  4490. +++ b/components/user_scripts/common/error_utils.h
  4491. @@ -0,0 +1,24 @@
  4492. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4493. +// Use of this source code is governed by a BSD-style license that can be
  4494. +// found in the LICENSE file.
  4495. +
  4496. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4497. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4498. +
  4499. +#include <string>
  4500. +
  4501. +#include "base/strings/string_piece.h"
  4502. +
  4503. +namespace user_scripts {
  4504. +
  4505. +class ErrorUtils {
  4506. + public:
  4507. + // Creates an error messages from a pattern.
  4508. + static std::string FormatErrorMessage(base::StringPiece format,
  4509. + base::StringPiece s1);
  4510. +
  4511. +};
  4512. +
  4513. +} // namespace extensions
  4514. +
  4515. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4516. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  4517. new file mode 100755
  4518. --- /dev/null
  4519. +++ b/components/user_scripts/common/extension_message_generator.cc
  4520. @@ -0,0 +1,29 @@
  4521. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4522. +// Use of this source code is governed by a BSD-style license that can be
  4523. +// found in the LICENSE file.
  4524. +
  4525. +// Get basic type definitions.
  4526. +#define IPC_MESSAGE_IMPL
  4527. +#include "components/user_scripts/common/extension_message_generator.h"
  4528. +
  4529. +// Generate constructors.
  4530. +#include "ipc/struct_constructor_macros.h"
  4531. +#include "components/user_scripts/common/extension_message_generator.h"
  4532. +
  4533. +// Generate param traits write methods.
  4534. +#include "ipc/param_traits_write_macros.h"
  4535. +namespace IPC {
  4536. +#include "components/user_scripts/common/extension_message_generator.h"
  4537. +} // namespace IPC
  4538. +
  4539. +// Generate param traits read methods.
  4540. +#include "ipc/param_traits_read_macros.h"
  4541. +namespace IPC {
  4542. +#include "components/user_scripts/common/extension_message_generator.h"
  4543. +} // namespace IPC
  4544. +
  4545. +// Generate param traits log methods.
  4546. +#include "ipc/param_traits_log_macros.h"
  4547. +namespace IPC {
  4548. +#include "components/user_scripts/common/extension_message_generator.h"
  4549. +} // namespace IPC
  4550. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  4551. new file mode 100755
  4552. --- /dev/null
  4553. +++ b/components/user_scripts/common/extension_message_generator.h
  4554. @@ -0,0 +1,11 @@
  4555. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4556. +// Use of this source code is governed by a BSD-style license that can be
  4557. +// found in the LICENSE file.
  4558. +
  4559. +// Multiply-included file, hence no include guard.
  4560. +
  4561. +#undef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4562. +#include "extension_messages.h"
  4563. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4564. +#error "Failed to include header extension_messages.h"
  4565. +#endif
  4566. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  4567. new file mode 100755
  4568. --- /dev/null
  4569. +++ b/components/user_scripts/common/extension_messages.cc
  4570. @@ -0,0 +1,40 @@
  4571. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4572. +// Use of this source code is governed by a BSD-style license that can be
  4573. +// found in the LICENSE file.
  4574. +
  4575. +#include "extension_messages.h"
  4576. +
  4577. +#include <stddef.h>
  4578. +
  4579. +#include <memory>
  4580. +#include <utility>
  4581. +
  4582. +#include "content/public/common/common_param_traits.h"
  4583. +
  4584. +namespace IPC {
  4585. +
  4586. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  4587. + WriteParam(m, p.type());
  4588. + WriteParam(m, p.id());
  4589. +}
  4590. +
  4591. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  4592. + base::PickleIterator* iter,
  4593. + param_type* r) {
  4594. + HostID::HostType type;
  4595. + std::string id;
  4596. + if (!ReadParam(m, iter, &type))
  4597. + return false;
  4598. + if (!ReadParam(m, iter, &id))
  4599. + return false;
  4600. + *r = HostID(type, id);
  4601. + return true;
  4602. +}
  4603. +
  4604. +void ParamTraits<HostID>::Log(
  4605. + const param_type& p, std::string* l) {
  4606. + LogParam(p.type(), l);
  4607. + LogParam(p.id(), l);
  4608. +}
  4609. +
  4610. +} // namespace IPC
  4611. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  4612. new file mode 100755
  4613. --- /dev/null
  4614. +++ b/components/user_scripts/common/extension_messages.h
  4615. @@ -0,0 +1,70 @@
  4616. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4617. +// Use of this source code is governed by a BSD-style license that can be
  4618. +// found in the LICENSE file.
  4619. +
  4620. +// IPC messages for extensions.
  4621. +
  4622. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4623. +#define USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4624. +
  4625. +#include <stdint.h>
  4626. +
  4627. +#include <map>
  4628. +#include <memory>
  4629. +#include <set>
  4630. +#include <string>
  4631. +#include <vector>
  4632. +
  4633. +#include "base/memory/read_only_shared_memory_region.h"
  4634. +#include "base/values.h"
  4635. +#include "content/public/common/common_param_traits.h"
  4636. +#include "constants.h"
  4637. +#include "host_id.h"
  4638. +#include "ipc/ipc_message_start.h"
  4639. +#include "ipc/ipc_message_macros.h"
  4640. +#include "url/gurl.h"
  4641. +#include "url/origin.h"
  4642. +
  4643. +#define IPC_MESSAGE_START ExtensionMsgStart
  4644. +
  4645. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  4646. +
  4647. +// Singly-included section for custom IPC traits.
  4648. +#ifndef INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4649. +#define INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4650. +
  4651. +namespace IPC {
  4652. +
  4653. +template <>
  4654. +struct ParamTraits<HostID> {
  4655. + typedef HostID param_type;
  4656. + static void Write(base::Pickle* m, const param_type& p);
  4657. + static bool Read(const base::Pickle* m,
  4658. + base::PickleIterator* iter,
  4659. + param_type* r);
  4660. + static void Log(const param_type& p, std::string* l);
  4661. +};
  4662. +
  4663. +
  4664. +} // namespace IPC
  4665. +
  4666. +#endif // INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4667. +
  4668. +// Notification that the user scripts have been updated. It has one
  4669. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  4670. +// This memory region is valid in the context of the renderer.
  4671. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  4672. +// programmatically-defined scripts. Otherwise, the handle refers to all
  4673. +// hosts' statically defined scripts. So far, only extension-hosts support
  4674. +// statically defined scripts; WebUI-hosts don't.
  4675. +// If |changed_hosts| is not empty, only the host in that set will
  4676. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  4677. +// region will be updated. Note that the empty set => all hosts case is not
  4678. +// supported for per-extension programmatically-defined script regions; in such
  4679. +// regions, the owner is expected to list itself as the only changed host.
  4680. +// If |whitelisted_only| is true, this process should only run whitelisted
  4681. +// scripts and not all user scripts.
  4682. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  4683. + base::ReadOnlySharedMemoryRegion)
  4684. +
  4685. +#endif // USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4686. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  4687. new file mode 100755
  4688. --- /dev/null
  4689. +++ b/components/user_scripts/common/host_id.cc
  4690. @@ -0,0 +1,31 @@
  4691. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4692. +// Use of this source code is governed by a BSD-style license that can be
  4693. +// found in the LICENSE file.
  4694. +
  4695. +#include "host_id.h"
  4696. +
  4697. +#include <tuple>
  4698. +
  4699. +HostID::HostID()
  4700. + : type_(HostType::EXTENSIONS) {
  4701. +}
  4702. +
  4703. +HostID::HostID(HostType type, const std::string& id)
  4704. + : type_(type), id_(id) {
  4705. +}
  4706. +
  4707. +HostID::HostID(const HostID& host_id)
  4708. + : type_(host_id.type()),
  4709. + id_(host_id.id()) {
  4710. +}
  4711. +
  4712. +HostID::~HostID() {
  4713. +}
  4714. +
  4715. +bool HostID::operator<(const HostID& host_id) const {
  4716. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  4717. +}
  4718. +
  4719. +bool HostID::operator==(const HostID& host_id) const {
  4720. + return type_ == host_id.type_ && id_ == host_id.id_;
  4721. +}
  4722. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  4723. new file mode 100755
  4724. --- /dev/null
  4725. +++ b/components/user_scripts/common/host_id.h
  4726. @@ -0,0 +1,35 @@
  4727. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4728. +// Use of this source code is governed by a BSD-style license that can be
  4729. +// found in the LICENSE file.
  4730. +
  4731. +#ifndef USERSCRIPTS_COMMON_HOST_ID_H_
  4732. +#define USERSCRIPTS_COMMON_HOST_ID_H_
  4733. +
  4734. +#include <string>
  4735. +
  4736. +// IDs of hosts who own user scripts.
  4737. +// A HostID is immutable after creation.
  4738. +struct HostID {
  4739. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  4740. +
  4741. + HostID();
  4742. + HostID(HostType type, const std::string& id);
  4743. + HostID(const HostID& host_id);
  4744. + ~HostID();
  4745. +
  4746. + bool operator<(const HostID& host_id) const;
  4747. + bool operator==(const HostID& host_id) const;
  4748. +
  4749. + HostType type() const { return type_; }
  4750. + const std::string& id() const { return id_; }
  4751. +
  4752. + private:
  4753. + // The type of the host.
  4754. + HostType type_;
  4755. +
  4756. + // Similar to extension_id, host_id is a unique indentifier for a host,
  4757. + // e.g., an Extension or WebUI.
  4758. + std::string id_;
  4759. +};
  4760. +
  4761. +#endif // USERSCRIPTS_COMMON_HOST_ID_H_
  4762. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  4763. new file mode 100755
  4764. --- /dev/null
  4765. +++ b/components/user_scripts/common/script_constants.h
  4766. @@ -0,0 +1,33 @@
  4767. +// Copyright 2020 The Chromium Authors. All rights reserved.
  4768. +// Use of this source code is governed by a BSD-style license that can be
  4769. +// found in the LICENSE file.
  4770. +
  4771. +#ifndef USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4772. +#define USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4773. +
  4774. +namespace user_scripts {
  4775. +
  4776. +// Whether to fall back to matching the origin for frames where the URL
  4777. +// cannot be matched directly, such as those with about: or data: schemes.
  4778. +enum class MatchOriginAsFallbackBehavior {
  4779. + // Never fall back on the origin; this means scripts will never match on
  4780. + // these frames.
  4781. + kNever,
  4782. + // Match the origin only for about:-scheme frames, and then climb the frame
  4783. + // tree to find an appropriate ancestor to get a full URL (including path).
  4784. + // This is for supporting the "match_about_blank" key.
  4785. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  4786. + // and not worry about climbing the frame tree. It would be a behavior
  4787. + // change, but I wonder how many extensions it would impact in practice.
  4788. + kMatchForAboutSchemeAndClimbTree,
  4789. + // Match the origin as a fallback whenever applicable. This won't have a
  4790. + // corresponding path.
  4791. + kAlways,
  4792. +};
  4793. +
  4794. +// TODO(devlin): Move the other non-UserScript-specific constants like
  4795. +// RunLocation and InjectionType from UserScript into here.
  4796. +
  4797. +}
  4798. +
  4799. +#endif // USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4800. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  4801. new file mode 100755
  4802. --- /dev/null
  4803. +++ b/components/user_scripts/common/url_pattern.cc
  4804. @@ -0,0 +1,803 @@
  4805. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4806. +// Use of this source code is governed by a BSD-style license that can be
  4807. +// found in the LICENSE file.
  4808. +
  4809. +#include "url_pattern.h"
  4810. +
  4811. +#include <stddef.h>
  4812. +
  4813. +#include <ostream>
  4814. +
  4815. +#include "base/logging.h"
  4816. +#include "base/strings/pattern.h"
  4817. +#include "base/strings/strcat.h"
  4818. +#include "base/strings/string_number_conversions.h"
  4819. +#include "base/strings/string_piece.h"
  4820. +#include "base/strings/string_split.h"
  4821. +#include "base/strings/string_util.h"
  4822. +#include "base/strings/stringprintf.h"
  4823. +#include "content/public/common/url_constants.h"
  4824. +#include "constants.h"
  4825. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4826. +#include "net/base/url_util.h"
  4827. +#include "url/gurl.h"
  4828. +#include "url/url_util.h"
  4829. +
  4830. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4831. +
  4832. +namespace {
  4833. +
  4834. +// TODO(aa): What about more obscure schemes like javascript: ?
  4835. +// Note: keep this array in sync with kValidSchemeMasks.
  4836. +const char* const kValidSchemes[] = {
  4837. + url::kHttpScheme, url::kHttpsScheme,
  4838. + url::kFileScheme, url::kFtpScheme,
  4839. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4840. + url::kFileSystemScheme, url::kWsScheme,
  4841. + url::kWssScheme, url::kDataScheme,
  4842. + url::kUrnScheme,
  4843. +};
  4844. +
  4845. +const int kValidSchemeMasks[] = {
  4846. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4847. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4848. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4849. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4850. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4851. + URLPattern::SCHEME_URN,
  4852. +};
  4853. +
  4854. +static_assert(base::size(kValidSchemes) == base::size(kValidSchemeMasks),
  4855. + "must keep these arrays in sync");
  4856. +
  4857. +const char kParseSuccess[] = "Success.";
  4858. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4859. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4860. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4861. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4862. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4863. +const char kParseErrorEmptyPath[] = "Empty path.";
  4864. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4865. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4866. +
  4867. +// Message explaining each URLPattern::ParseResult.
  4868. +const char* const kParseResultMessages[] = {
  4869. + kParseSuccess,
  4870. + kParseErrorMissingSchemeSeparator,
  4871. + kParseErrorInvalidScheme,
  4872. + kParseErrorWrongSchemeType,
  4873. + kParseErrorEmptyHost,
  4874. + kParseErrorInvalidHostWildcard,
  4875. + kParseErrorEmptyPath,
  4876. + kParseErrorInvalidPort,
  4877. + kParseErrorInvalidHost,
  4878. +};
  4879. +
  4880. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4881. + base::size(kParseResultMessages),
  4882. + "must add message for each parse result");
  4883. +
  4884. +const char kPathSeparator[] = "/";
  4885. +
  4886. +bool IsStandardScheme(base::StringPiece scheme) {
  4887. + // "*" gets the same treatment as a standard scheme.
  4888. + if (scheme == "*")
  4889. + return true;
  4890. +
  4891. + return url::IsStandard(scheme.data(),
  4892. + url::Component(0, static_cast<int>(scheme.length())));
  4893. +}
  4894. +
  4895. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4896. + if (port == "*")
  4897. + return true;
  4898. +
  4899. + // Only accept non-wildcard ports if the scheme uses ports.
  4900. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4901. + url::PORT_UNSPECIFIED) {
  4902. + return false;
  4903. + }
  4904. +
  4905. + int parsed_port = url::PORT_UNSPECIFIED;
  4906. + if (!base::StringToInt(port, &parsed_port))
  4907. + return false;
  4908. + return (parsed_port >= 0) && (parsed_port < 65536);
  4909. +}
  4910. +
  4911. +// Returns |path| with the trailing wildcard stripped if one existed.
  4912. +//
  4913. +// The functions that rely on this (OverlapsWith and Contains) are only
  4914. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4915. +// the path will have only a single wildcard at the end. This makes figuring
  4916. +// out overlap much easier. It seems like there is probably a computer-sciency
  4917. +// way to solve the general case, but we don't need that yet.
  4918. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4919. + if (base::EndsWith(path, "*"))
  4920. + path.remove_suffix(1);
  4921. + return path;
  4922. +}
  4923. +
  4924. +// Removes trailing dot from |host_piece| if any.
  4925. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4926. + if (base::EndsWith(host_piece, "."))
  4927. + host_piece.remove_suffix(1);
  4928. + return host_piece;
  4929. +}
  4930. +
  4931. +} // namespace
  4932. +
  4933. +// static
  4934. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4935. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4936. + if (scheme == kValidSchemes[i])
  4937. + return true;
  4938. + }
  4939. + return false;
  4940. +}
  4941. +
  4942. +// static
  4943. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4944. + int result = 0;
  4945. + for (size_t i = 0; i < base::size(kValidSchemeMasks); ++i)
  4946. + result |= kValidSchemeMasks[i];
  4947. + return result;
  4948. +}
  4949. +
  4950. +URLPattern::URLPattern()
  4951. + : valid_schemes_(SCHEME_NONE),
  4952. + match_all_urls_(false),
  4953. + match_subdomains_(false),
  4954. + port_("*") {}
  4955. +
  4956. +URLPattern::URLPattern(int valid_schemes)
  4957. + : valid_schemes_(valid_schemes),
  4958. + match_all_urls_(false),
  4959. + match_subdomains_(false),
  4960. + port_("*") {}
  4961. +
  4962. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4963. + // Strict error checking is used, because this constructor is only
  4964. + // appropriate when we know |pattern| is valid.
  4965. + : valid_schemes_(valid_schemes),
  4966. + match_all_urls_(false),
  4967. + match_subdomains_(false),
  4968. + port_("*") {
  4969. + ParseResult result = Parse(pattern);
  4970. + DCHECK_EQ(ParseResult::kSuccess, result)
  4971. + << "Parsing unexpectedly failed for pattern: " << pattern << ": "
  4972. + << GetParseResultString(result);
  4973. +}
  4974. +
  4975. +URLPattern::URLPattern(const URLPattern& other) = default;
  4976. +
  4977. +URLPattern::URLPattern(URLPattern&& other) = default;
  4978. +
  4979. +URLPattern::~URLPattern() {
  4980. +}
  4981. +
  4982. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4983. +
  4984. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4985. +
  4986. +bool URLPattern::operator<(const URLPattern& other) const {
  4987. + return GetAsString() < other.GetAsString();
  4988. +}
  4989. +
  4990. +bool URLPattern::operator>(const URLPattern& other) const {
  4991. + return GetAsString() > other.GetAsString();
  4992. +}
  4993. +
  4994. +bool URLPattern::operator==(const URLPattern& other) const {
  4995. + return GetAsString() == other.GetAsString();
  4996. +}
  4997. +
  4998. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4999. + return out << '"' << url_pattern.GetAsString() << '"';
  5000. +}
  5001. +
  5002. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  5003. + spec_.clear();
  5004. + SetMatchAllURLs(false);
  5005. + SetMatchSubdomains(false);
  5006. + SetPort("*");
  5007. +
  5008. + // Special case pattern to match every valid URL.
  5009. + if (pattern == kAllUrlsPattern) {
  5010. + SetMatchAllURLs(true);
  5011. + return ParseResult::kSuccess;
  5012. + }
  5013. +
  5014. + // Parse out the scheme.
  5015. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  5016. + bool has_standard_scheme_separator = true;
  5017. +
  5018. + // Some urls also use ':' alone as the scheme separator.
  5019. + if (scheme_end_pos == base::StringPiece::npos) {
  5020. + scheme_end_pos = pattern.find(':');
  5021. + has_standard_scheme_separator = false;
  5022. + }
  5023. +
  5024. + if (scheme_end_pos == base::StringPiece::npos)
  5025. + return ParseResult::kMissingSchemeSeparator;
  5026. +
  5027. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  5028. + return ParseResult::kInvalidScheme;
  5029. +
  5030. + bool standard_scheme = IsStandardScheme(scheme_);
  5031. + if (standard_scheme != has_standard_scheme_separator)
  5032. + return ParseResult::kWrongSchemeSeparator;
  5033. +
  5034. + // Advance past the scheme separator.
  5035. + scheme_end_pos +=
  5036. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  5037. + if (scheme_end_pos >= pattern.size())
  5038. + return ParseResult::kEmptyHost;
  5039. +
  5040. + // Parse out the host and path.
  5041. + size_t host_start_pos = scheme_end_pos;
  5042. + size_t path_start_pos = 0;
  5043. +
  5044. + if (!standard_scheme) {
  5045. + path_start_pos = host_start_pos;
  5046. + } else if (scheme_ == url::kFileScheme) {
  5047. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5048. + if (host_end_pos == base::StringPiece::npos) {
  5049. + // Allow hostname omission.
  5050. + // e.g. file://* is interpreted as file:///*,
  5051. + // file://foo* is interpreted as file:///foo*.
  5052. + path_start_pos = host_start_pos - 1;
  5053. + } else {
  5054. + // Ignore hostname if scheme is file://.
  5055. + // e.g. file://localhost/foo is equal to file:///foo.
  5056. + path_start_pos = host_end_pos;
  5057. + }
  5058. + } else {
  5059. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5060. +
  5061. + // Host is required.
  5062. + if (host_start_pos == host_end_pos)
  5063. + return ParseResult::kEmptyHost;
  5064. +
  5065. + if (host_end_pos == base::StringPiece::npos)
  5066. + return ParseResult::kEmptyPath;
  5067. +
  5068. + base::StringPiece host_and_port =
  5069. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  5070. +
  5071. + size_t port_separator_pos = base::StringPiece::npos;
  5072. + if (host_and_port[0] != '[') {
  5073. + // Not IPv6 (either IPv4 or just a normal address).
  5074. + port_separator_pos = host_and_port.find(':');
  5075. + } else { // IPv6.
  5076. + size_t host_end_pos = host_and_port.find(']');
  5077. + if (host_end_pos == base::StringPiece::npos)
  5078. + return ParseResult::kInvalidHost;
  5079. + if (host_end_pos == 1)
  5080. + return ParseResult::kEmptyHost;
  5081. +
  5082. + if (host_end_pos < host_and_port.length() - 1) {
  5083. + // The host isn't the only component. Check for a port. This would
  5084. + // require a ':' to follow the closing ']' from the host.
  5085. + if (host_and_port[host_end_pos + 1] != ':')
  5086. + return ParseResult::kInvalidHost;
  5087. +
  5088. + port_separator_pos = host_end_pos + 1;
  5089. + }
  5090. + }
  5091. +
  5092. + if (port_separator_pos != base::StringPiece::npos &&
  5093. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  5094. + return ParseResult::kInvalidPort;
  5095. + }
  5096. +
  5097. + // Note: this substr() will be the entire string if the port position
  5098. + // wasn't found.
  5099. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  5100. +
  5101. + if (host_piece.empty())
  5102. + return ParseResult::kEmptyHost;
  5103. +
  5104. + if (host_piece == "*") {
  5105. + match_subdomains_ = true;
  5106. + host_piece = base::StringPiece();
  5107. + } else if (base::StartsWith(host_piece, "*.")) {
  5108. + if (host_piece.length() == 2) {
  5109. + // We don't allow just '*.' as a host.
  5110. + return ParseResult::kEmptyHost;
  5111. + }
  5112. + match_subdomains_ = true;
  5113. + host_piece = host_piece.substr(2);
  5114. + }
  5115. +
  5116. + host_ = std::string(host_piece);
  5117. +
  5118. + path_start_pos = host_end_pos;
  5119. + }
  5120. +
  5121. + SetPath(pattern.substr(path_start_pos));
  5122. +
  5123. + // No other '*' can occur in the host, though. This isn't necessary, but is
  5124. + // done as a convenience to developers who might otherwise be confused and
  5125. + // think '*' works as a glob in the host.
  5126. + if (host_.find('*') != std::string::npos)
  5127. + return ParseResult::kInvalidHostWildcard;
  5128. +
  5129. + if (!host_.empty()) {
  5130. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  5131. + // it.
  5132. + url::CanonHostInfo host_info;
  5133. + host_ = net::CanonicalizeHost(host_, &host_info);
  5134. + // net::CanonicalizeHost() returns an empty string on failure.
  5135. + if (host_.empty())
  5136. + return ParseResult::kInvalidHost;
  5137. + }
  5138. +
  5139. + // Null characters are not allowed in hosts.
  5140. + if (host_.find('\0') != std::string::npos)
  5141. + return ParseResult::kInvalidHost;
  5142. +
  5143. + return ParseResult::kSuccess;
  5144. +}
  5145. +
  5146. +void URLPattern::SetValidSchemes(int valid_schemes) {
  5147. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  5148. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  5149. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  5150. + // http or https).
  5151. + spec_.clear();
  5152. + valid_schemes_ = valid_schemes;
  5153. +}
  5154. +
  5155. +void URLPattern::SetHost(base::StringPiece host) {
  5156. + spec_.clear();
  5157. + host_.assign(host.data(), host.size());
  5158. +}
  5159. +
  5160. +void URLPattern::SetMatchAllURLs(bool val) {
  5161. + spec_.clear();
  5162. + match_all_urls_ = val;
  5163. +
  5164. + if (val) {
  5165. + match_subdomains_ = true;
  5166. + scheme_ = "*";
  5167. + host_.clear();
  5168. + SetPath("/*");
  5169. + }
  5170. +}
  5171. +
  5172. +void URLPattern::SetMatchSubdomains(bool val) {
  5173. + spec_.clear();
  5174. + match_subdomains_ = val;
  5175. +}
  5176. +
  5177. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  5178. + spec_.clear();
  5179. + scheme_.assign(scheme.data(), scheme.size());
  5180. + if (scheme_ == "*") {
  5181. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  5182. + } else if (!IsValidScheme(scheme_)) {
  5183. + return false;
  5184. + }
  5185. + return true;
  5186. +}
  5187. +
  5188. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  5189. + if (valid_schemes_ == SCHEME_ALL)
  5190. + return true;
  5191. +
  5192. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5193. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  5194. + return true;
  5195. + }
  5196. +
  5197. + return false;
  5198. +}
  5199. +
  5200. +void URLPattern::SetPath(base::StringPiece path) {
  5201. + spec_.clear();
  5202. + path_.assign(path.data(), path.size());
  5203. + path_escaped_ = path_;
  5204. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  5205. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  5206. +}
  5207. +
  5208. +bool URLPattern::SetPort(base::StringPiece port) {
  5209. + spec_.clear();
  5210. + if (IsValidPortForScheme(scheme_, port)) {
  5211. + port_.assign(port.data(), port.size());
  5212. + return true;
  5213. + }
  5214. + return false;
  5215. +}
  5216. +
  5217. +bool URLPattern::MatchesURL(const GURL& test) const {
  5218. + // Invalid URLs can never match.
  5219. + if (!test.is_valid())
  5220. + return false;
  5221. +
  5222. + const GURL* test_url = &test;
  5223. + bool has_inner_url = test.inner_url() != nullptr;
  5224. +
  5225. + if (has_inner_url) {
  5226. + if (!test.SchemeIsFileSystem())
  5227. + return false; // The only nested URLs we handle are filesystem URLs.
  5228. + test_url = test.inner_url();
  5229. + }
  5230. +
  5231. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  5232. + // the scheme is excluded.
  5233. + if (!MatchesScheme(test_url->scheme_piece()))
  5234. + return false;
  5235. +
  5236. + if (match_all_urls_)
  5237. + return true;
  5238. +
  5239. + // Unless |match_all_urls_| is true, the grammar only permits matching
  5240. + // URLs with nonempty paths.
  5241. + if (!test.has_path())
  5242. + return false;
  5243. +
  5244. + std::string path_for_request = test.PathForRequest();
  5245. + if (has_inner_url) {
  5246. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  5247. + path_for_request.c_str());
  5248. + }
  5249. +
  5250. + return MatchesSecurityOriginHelper(*test_url) &&
  5251. + MatchesPath(path_for_request);
  5252. +}
  5253. +
  5254. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  5255. + const GURL* test_url = &test;
  5256. + bool has_inner_url = test.inner_url() != NULL;
  5257. +
  5258. + if (has_inner_url) {
  5259. + if (!test.SchemeIsFileSystem())
  5260. + return false; // The only nested URLs we handle are filesystem URLs.
  5261. + test_url = test.inner_url();
  5262. + }
  5263. +
  5264. + if (!MatchesScheme(test_url->scheme()))
  5265. + return false;
  5266. +
  5267. + if (match_all_urls_)
  5268. + return true;
  5269. +
  5270. + return MatchesSecurityOriginHelper(*test_url);
  5271. +}
  5272. +
  5273. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  5274. + if (!IsValidScheme(test))
  5275. + return false;
  5276. +
  5277. + return scheme_ == "*" || test == scheme_;
  5278. +}
  5279. +
  5280. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  5281. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  5282. + // important that we do this conversion to a GURL in order to canonicalize the
  5283. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  5284. + // just do string comparison.
  5285. + return MatchesHost(
  5286. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  5287. + url::kStandardSchemeSeparator, host.data())));
  5288. +}
  5289. +
  5290. +bool URLPattern::MatchesHost(const GURL& test) const {
  5291. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  5292. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  5293. +
  5294. + // If the hosts are exactly equal, we have a match.
  5295. + if (test_host == pattern_host)
  5296. + return true;
  5297. +
  5298. + // If we're matching subdomains, and we have no host in the match pattern,
  5299. + // that means that we're matching all hosts, which means we have a match no
  5300. + // matter what the test host is.
  5301. + if (match_subdomains_ && pattern_host.empty())
  5302. + return true;
  5303. +
  5304. + // Otherwise, we can only match if our match pattern matches subdomains.
  5305. + if (!match_subdomains_)
  5306. + return false;
  5307. +
  5308. + // We don't do subdomain matching against IP addresses, so we can give up now
  5309. + // if the test host is an IP address.
  5310. + if (test.HostIsIPAddress())
  5311. + return false;
  5312. +
  5313. + // Check if the test host is a subdomain of our host.
  5314. + if (test_host.length() <= (pattern_host.length() + 1))
  5315. + return false;
  5316. +
  5317. + if (!base::EndsWith(test_host, pattern_host))
  5318. + return false;
  5319. +
  5320. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  5321. +}
  5322. +
  5323. +bool URLPattern::MatchesEffectiveTld(
  5324. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  5325. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  5326. + const {
  5327. + // Check if it matches all urls or is a pattern like http://*/*.
  5328. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  5329. + return true;
  5330. +
  5331. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  5332. + if (!match_subdomains_)
  5333. + return false;
  5334. +
  5335. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  5336. + // doesn't match all hosts in an effective TLD.
  5337. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5338. + host_, unknown_filter, private_filter)) {
  5339. + return false;
  5340. + }
  5341. +
  5342. + // At this point the host could either be just a TLD ("com") or some unknown
  5343. + // TLD-like string ("notatld"). To disambiguate between them construct a
  5344. + // fake URL, and check the registry.
  5345. + //
  5346. + // If we recognized this TLD, then this is a pattern like *.com, and it
  5347. + // matches an effective TLD.
  5348. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5349. + "notatld." + host_, unknown_filter, private_filter);
  5350. +}
  5351. +
  5352. +bool URLPattern::MatchesSingleOrigin() const {
  5353. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  5354. + // defaults to *. It's not very interesting anyway, so leave it out.
  5355. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  5356. +}
  5357. +
  5358. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  5359. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  5360. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  5361. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  5362. + if (path_escaped_.length() == test.length() + 2 &&
  5363. + base::StartsWith(path_escaped_.c_str(), test) &&
  5364. + base::EndsWith(path_escaped_, "/*")) {
  5365. + return true;
  5366. + }
  5367. +
  5368. + return base::MatchPattern(test, path_escaped_);
  5369. +}
  5370. +
  5371. +const std::string& URLPattern::GetAsString() const {
  5372. + if (!spec_.empty())
  5373. + return spec_;
  5374. +
  5375. + if (match_all_urls_) {
  5376. + spec_ = kAllUrlsPattern;
  5377. + return spec_;
  5378. + }
  5379. +
  5380. + bool standard_scheme = IsStandardScheme(scheme_);
  5381. +
  5382. + std::string spec = scheme_ +
  5383. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  5384. +
  5385. + if (scheme_ != url::kFileScheme && standard_scheme) {
  5386. + if (match_subdomains_) {
  5387. + spec += "*";
  5388. + if (!host_.empty())
  5389. + spec += ".";
  5390. + }
  5391. +
  5392. + if (!host_.empty())
  5393. + spec += host_;
  5394. +
  5395. + if (port_ != "*") {
  5396. + spec += ":";
  5397. + spec += port_;
  5398. + }
  5399. + }
  5400. +
  5401. + if (!path_.empty())
  5402. + spec += path_;
  5403. +
  5404. + spec_ = std::move(spec);
  5405. + return spec_;
  5406. +}
  5407. +
  5408. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  5409. + if (match_all_urls() || other.match_all_urls())
  5410. + return true;
  5411. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  5412. + other.MatchesAnyScheme(GetExplicitSchemes()))
  5413. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  5414. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  5415. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  5416. + other.MatchesPath(StripTrailingWildcard(path())));
  5417. +}
  5418. +
  5419. +bool URLPattern::Contains(const URLPattern& other) const {
  5420. + // Important: it's not enough to just check match_all_urls(); we also need to
  5421. + // make sure that the schemes in this pattern are a superset of those in
  5422. + // |other|.
  5423. + if (match_all_urls() &&
  5424. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  5425. + return true;
  5426. + }
  5427. +
  5428. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  5429. + MatchesHost(other.host()) &&
  5430. + (!other.match_subdomains_ || match_subdomains_) &&
  5431. + MatchesPortPattern(other.port()) &&
  5432. + MatchesPath(StripTrailingWildcard(other.path()));
  5433. +}
  5434. +
  5435. +absl::optional<URLPattern> URLPattern::CreateIntersection(
  5436. + const URLPattern& other) const {
  5437. + // Easy case: Schemes don't overlap. Return nullopt.
  5438. + int intersection_schemes = URLPattern::SCHEME_NONE;
  5439. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  5440. + intersection_schemes = other.valid_schemes_;
  5441. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  5442. + intersection_schemes = valid_schemes_;
  5443. + else
  5444. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  5445. +
  5446. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  5447. + return absl::nullopt;
  5448. +
  5449. + {
  5450. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  5451. + // This can happen when either:
  5452. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  5453. + // - One of the patterns has match_all_urls() equal to true.
  5454. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  5455. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  5456. + // from the path, which could yield the incorrect result.
  5457. + const URLPattern* copy_source = nullptr;
  5458. + if (*this == other || other.match_all_urls())
  5459. + copy_source = this;
  5460. + else if (match_all_urls())
  5461. + copy_source = &other;
  5462. +
  5463. + if (copy_source) {
  5464. + // NOTE: equality checks don't take into account valid_schemes_, and
  5465. + // schemes can be different in the case of match_all_urls() as well, so
  5466. + // we can't always just return *copy_source.
  5467. + if (intersection_schemes == copy_source->valid_schemes_)
  5468. + return *copy_source;
  5469. + URLPattern result(intersection_schemes);
  5470. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  5471. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  5472. + return result;
  5473. + }
  5474. + }
  5475. +
  5476. + // No more easy cases. Go through component by component to find the patterns
  5477. + // that intersect.
  5478. +
  5479. + // Note: Alias the function type (rather than using auto) because
  5480. + // MatchesHost() is overloaded.
  5481. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  5482. +
  5483. + auto get_intersection = [this, &other](base::StringPiece own_str,
  5484. + base::StringPiece other_str,
  5485. + match_function_type match_function,
  5486. + base::StringPiece* out) {
  5487. + if ((this->*match_function)(other_str)) {
  5488. + *out = other_str;
  5489. + return true;
  5490. + }
  5491. + if ((other.*match_function)(own_str)) {
  5492. + *out = own_str;
  5493. + return true;
  5494. + }
  5495. + return false;
  5496. + };
  5497. +
  5498. + base::StringPiece scheme;
  5499. + base::StringPiece host;
  5500. + base::StringPiece port;
  5501. + base::StringPiece path;
  5502. + // If any pieces fail to overlap, then there is no intersection.
  5503. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  5504. + &scheme) ||
  5505. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  5506. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  5507. + &port) ||
  5508. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  5509. + return absl::nullopt;
  5510. + }
  5511. +
  5512. + // Only match subdomains if both patterns match subdomains.
  5513. + base::StringPiece subdomains;
  5514. + if (match_subdomains_ && other.match_subdomains_) {
  5515. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  5516. + // append '*' instead of '*.'.
  5517. + subdomains = host.empty() ? "*" : "*.";
  5518. + }
  5519. +
  5520. + base::StringPiece scheme_separator =
  5521. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  5522. +
  5523. + std::string pattern_str = base::StrCat(
  5524. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  5525. +
  5526. + URLPattern pattern(intersection_schemes);
  5527. + ParseResult result = pattern.Parse(pattern_str);
  5528. + // TODO(devlin): I don't think there's any way this should ever fail, but
  5529. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  5530. + // to a DCHECK in M72.
  5531. + CHECK_EQ(ParseResult::kSuccess, result);
  5532. +
  5533. + return pattern;
  5534. +}
  5535. +
  5536. +bool URLPattern::MatchesAnyScheme(
  5537. + const std::vector<std::string>& schemes) const {
  5538. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5539. + if (MatchesScheme(*i))
  5540. + return true;
  5541. + }
  5542. +
  5543. + return false;
  5544. +}
  5545. +
  5546. +bool URLPattern::MatchesAllSchemes(
  5547. + const std::vector<std::string>& schemes) const {
  5548. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5549. + if (!MatchesScheme(*i))
  5550. + return false;
  5551. + }
  5552. +
  5553. + return true;
  5554. +}
  5555. +
  5556. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  5557. + // Ignore hostname if scheme is file://.
  5558. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  5559. + return false;
  5560. +
  5561. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  5562. + return false;
  5563. +
  5564. + return true;
  5565. +}
  5566. +
  5567. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  5568. + return port_ == "*" || port_ == port;
  5569. +}
  5570. +
  5571. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  5572. + std::vector<std::string> result;
  5573. +
  5574. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  5575. + result.push_back(scheme_);
  5576. + return result;
  5577. + }
  5578. +
  5579. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5580. + if (MatchesScheme(kValidSchemes[i])) {
  5581. + result.push_back(kValidSchemes[i]);
  5582. + }
  5583. + }
  5584. +
  5585. + return result;
  5586. +}
  5587. +
  5588. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  5589. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  5590. + std::vector<URLPattern> result;
  5591. +
  5592. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  5593. + i != explicit_schemes.end(); ++i) {
  5594. + URLPattern temp = *this;
  5595. + temp.SetScheme(*i);
  5596. + temp.SetMatchAllURLs(false);
  5597. + result.push_back(temp);
  5598. + }
  5599. +
  5600. + return result;
  5601. +}
  5602. +
  5603. +// static
  5604. +const char* URLPattern::GetParseResultString(
  5605. + URLPattern::ParseResult parse_result) {
  5606. + return kParseResultMessages[static_cast<int>(parse_result)];
  5607. +}
  5608. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  5609. new file mode 100755
  5610. --- /dev/null
  5611. +++ b/components/user_scripts/common/url_pattern.h
  5612. @@ -0,0 +1,302 @@
  5613. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5614. +// Use of this source code is governed by a BSD-style license that can be
  5615. +// found in the LICENSE file.
  5616. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_H_
  5617. +#define USERSCRIPTS_COMMON_URL_PATTERN_H_
  5618. +
  5619. +#include <functional>
  5620. +#include <iosfwd>
  5621. +#include <string>
  5622. +#include <vector>
  5623. +
  5624. +#include "base/strings/string_piece.h"
  5625. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  5626. +
  5627. +class GURL;
  5628. +
  5629. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  5630. +// subset of URL syntax:
  5631. +//
  5632. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  5633. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  5634. +// 'chrome-extension' | 'filesystem'
  5635. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  5636. +// '*.' <anychar except '/' and '*'>+
  5637. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  5638. +// <path> := '/' <any chars>
  5639. +//
  5640. +// * Host is not used when the scheme is 'file'.
  5641. +// * The path can have embedded '*' characters which act as glob wildcards.
  5642. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  5643. +// a valid scheme (as specified by valid_schemes_).
  5644. +// * The '*' scheme pattern excludes file URLs.
  5645. +//
  5646. +// Examples of valid patterns:
  5647. +// - http://*/*
  5648. +// - http://*/foo*
  5649. +// - https://*.google.com/foo*bar
  5650. +// - file://monkey*
  5651. +// - http://127.0.0.1/*
  5652. +// - http://[2607:f8b0:4005:805::200e]/*
  5653. +//
  5654. +// Examples of invalid patterns:
  5655. +// - http://* -- path not specified
  5656. +// - http://*foo/bar -- * not allowed as substring of host component
  5657. +// - http://foo.*.bar/baz -- * must be first component
  5658. +// - http:/bar -- scheme separator not found
  5659. +// - foo://* -- invalid scheme
  5660. +// - chrome:// -- we don't support chrome internal URLs
  5661. +class URLPattern {
  5662. + public:
  5663. + // A collection of scheme bitmasks for use with valid_schemes.
  5664. + enum SchemeMasks {
  5665. + SCHEME_NONE = 0,
  5666. + SCHEME_HTTP = 1 << 0,
  5667. + SCHEME_HTTPS = 1 << 1,
  5668. + SCHEME_FILE = 1 << 2,
  5669. + SCHEME_FTP = 1 << 3,
  5670. + SCHEME_CHROMEUI = 1 << 4,
  5671. + SCHEME_EXTENSION = 1 << 5,
  5672. + SCHEME_FILESYSTEM = 1 << 6,
  5673. + SCHEME_WS = 1 << 7,
  5674. + SCHEME_WSS = 1 << 8,
  5675. + SCHEME_DATA = 1 << 9,
  5676. + SCHEME_URN = 1 << 10,
  5677. +
  5678. + // IMPORTANT!
  5679. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  5680. + // extension://, about:, etc. Because this has lots of security
  5681. + // implications, third-party extensions should usually not be able to get
  5682. + // access to URL patterns initialized this way. If there is a reason
  5683. + // for violating this general rule, document why this it safe.
  5684. + SCHEME_ALL = -1,
  5685. + };
  5686. +
  5687. + // Error codes returned from Parse().
  5688. + enum class ParseResult {
  5689. + kSuccess = 0,
  5690. + kMissingSchemeSeparator,
  5691. + kInvalidScheme,
  5692. + kWrongSchemeSeparator,
  5693. + kEmptyHost,
  5694. + kInvalidHostWildcard,
  5695. + kEmptyPath,
  5696. + kInvalidPort,
  5697. + kInvalidHost,
  5698. + kNumParseResults,
  5699. + };
  5700. +
  5701. + // The <all_urls> string pattern.
  5702. + static const char kAllUrlsPattern[];
  5703. +
  5704. + // Returns true if the given |scheme| is considered valid for extensions.
  5705. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  5706. +
  5707. + // Returns the mask for all schemes considered valid for extensions.
  5708. + static int GetValidSchemeMaskForExtensions();
  5709. +
  5710. + explicit URLPattern(int valid_schemes);
  5711. +
  5712. + // Convenience to construct a URLPattern from a string. If the string is not
  5713. + // known ahead of time, use Parse() instead, which returns success or failure.
  5714. + URLPattern(int valid_schemes, base::StringPiece pattern);
  5715. +
  5716. + URLPattern();
  5717. + URLPattern(const URLPattern& other);
  5718. + URLPattern(URLPattern&& other);
  5719. + ~URLPattern();
  5720. +
  5721. + URLPattern& operator=(const URLPattern& other);
  5722. + URLPattern& operator=(URLPattern&& other);
  5723. +
  5724. + bool operator<(const URLPattern& other) const;
  5725. + bool operator>(const URLPattern& other) const;
  5726. + bool operator==(const URLPattern& other) const;
  5727. +
  5728. + // Initializes this instance by parsing the provided string. Returns
  5729. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  5730. + // On failure, this instance will have some intermediate values and is in an
  5731. + // invalid state.
  5732. + ParseResult Parse(base::StringPiece pattern_str);
  5733. +
  5734. + // Gets the bitmask of valid schemes.
  5735. + int valid_schemes() const { return valid_schemes_; }
  5736. + void SetValidSchemes(int valid_schemes);
  5737. +
  5738. + // Gets the host the pattern matches. This can be an empty string if the
  5739. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  5740. + const std::string& host() const { return host_; }
  5741. + void SetHost(base::StringPiece host);
  5742. +
  5743. + // Gets whether to match subdomains of host().
  5744. + bool match_subdomains() const { return match_subdomains_; }
  5745. + void SetMatchSubdomains(bool val);
  5746. +
  5747. + // Gets the path the pattern matches with the leading slash. This can have
  5748. + // embedded asterisks which are interpreted using glob rules.
  5749. + const std::string& path() const { return path_; }
  5750. + void SetPath(base::StringPiece path);
  5751. +
  5752. + // Returns true if this pattern matches all (valid) urls.
  5753. + bool match_all_urls() const { return match_all_urls_; }
  5754. + void SetMatchAllURLs(bool val);
  5755. +
  5756. + // Sets the scheme for pattern matches. This can be a single '*' if the
  5757. + // pattern matches all valid schemes (as defined by the valid_schemes_
  5758. + // property). Returns false on failure (if the scheme is not valid).
  5759. + bool SetScheme(base::StringPiece scheme);
  5760. + // Note: You should use MatchesScheme() instead of this getter unless you
  5761. + // absolutely need the exact scheme. This is exposed for testing.
  5762. + const std::string& scheme() const { return scheme_; }
  5763. +
  5764. + // Returns true if the specified scheme can be used in this URL pattern, and
  5765. + // false otherwise. Uses valid_schemes_ to determine validity.
  5766. + bool IsValidScheme(base::StringPiece scheme) const;
  5767. +
  5768. + // Returns true if this instance matches the specified URL. Always returns
  5769. + // false for invalid URLs.
  5770. + bool MatchesURL(const GURL& test) const;
  5771. +
  5772. + // Returns true if this instance matches the specified security origin.
  5773. + bool MatchesSecurityOrigin(const GURL& test) const;
  5774. +
  5775. + // Returns true if |test| matches our scheme.
  5776. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  5777. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  5778. + // of the outer "filesystem:" part.
  5779. + bool MatchesScheme(base::StringPiece test) const;
  5780. +
  5781. + // Returns true if |test| matches our host.
  5782. + bool MatchesHost(base::StringPiece test) const;
  5783. + bool MatchesHost(const GURL& test) const;
  5784. +
  5785. + // Returns true if |test| matches our path.
  5786. + bool MatchesPath(base::StringPiece test) const;
  5787. +
  5788. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  5789. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  5790. + // matches all domains (e.g., *://*/*) will return true.
  5791. + // |private_filter| specifies whether private registries (like appspot.com)
  5792. + // should be considered; if included, patterns like *://*.appspot.com/* will
  5793. + // return true. By default, we exclude private registries (so *.appspot.com
  5794. + // returns false).
  5795. + // Note: This is an expensive method, and should be used sparingly!
  5796. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  5797. + // cached.
  5798. + bool MatchesEffectiveTld(
  5799. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  5800. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  5801. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  5802. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  5803. +
  5804. + // Returns true if the pattern only matches a single origin. The pattern may
  5805. + // include a path.
  5806. + bool MatchesSingleOrigin() const;
  5807. +
  5808. + // Sets the port. Returns false if the port is invalid.
  5809. + bool SetPort(base::StringPiece port);
  5810. + const std::string& port() const { return port_; }
  5811. +
  5812. + // Returns a string representing this instance.
  5813. + const std::string& GetAsString() const;
  5814. +
  5815. + // Determines whether there is a URL that would match this instance and
  5816. + // another instance. This method is symmetrical: Calling
  5817. + // other.OverlapsWith(this) would result in the same answer.
  5818. + bool OverlapsWith(const URLPattern& other) const;
  5819. +
  5820. + // Returns true if this pattern matches all possible URLs that |other| can
  5821. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5822. + bool Contains(const URLPattern& other) const;
  5823. +
  5824. + // Creates a new URLPattern that represents the intersection of this
  5825. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5826. + // For instance, given the patterns http://*.google.com/* and
  5827. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5828. + // NOTES:
  5829. + // - Though scheme intersections are supported, the serialization of
  5830. + // URLPatternSet does not record them. Be sure that this is safe for your
  5831. + // use cases.
  5832. + // - Path intersection is done on a best-effort basis. If one path clearly
  5833. + // contains another, it will be handled correctly, but this method does not
  5834. + // deal with cases like /*a* and /*b* (where technically the intersection
  5835. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5836. + absl::optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5837. +
  5838. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5839. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5840. + // wildcard scheme, then the returned set will contain one element that is
  5841. + // equivalent to this instance.
  5842. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5843. +
  5844. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5845. + if (a.match_all_urls_ && b.match_all_urls_)
  5846. + return false;
  5847. + return a.host_.compare(b.host_) < 0;
  5848. + }
  5849. +
  5850. + // Used for origin comparisons in a std::set.
  5851. + class EffectiveHostCompareFunctor {
  5852. + public:
  5853. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5854. + return EffectiveHostCompare(a, b);
  5855. + }
  5856. + };
  5857. +
  5858. + // Get an error string for a ParseResult.
  5859. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5860. +
  5861. + private:
  5862. + // Returns true if any of the |schemes| items matches our scheme.
  5863. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5864. +
  5865. + // Returns true if all of the |schemes| items matches our scheme.
  5866. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5867. +
  5868. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5869. +
  5870. + // Returns true if our port matches the |port| pattern (it may be "*").
  5871. + bool MatchesPortPattern(base::StringPiece port) const;
  5872. +
  5873. + // If the URLPattern contains a wildcard scheme, returns a list of
  5874. + // equivalent literal schemes, otherwise returns the current scheme.
  5875. + std::vector<std::string> GetExplicitSchemes() const;
  5876. +
  5877. + // A bitmask containing the schemes which are considered valid for this
  5878. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5879. + // scheme.
  5880. + int valid_schemes_;
  5881. +
  5882. + // True if this is a special-case "<all_urls>" pattern.
  5883. + bool match_all_urls_;
  5884. +
  5885. + // The scheme for the pattern.
  5886. + std::string scheme_;
  5887. +
  5888. + // The host without any leading "*" components.
  5889. + std::string host_;
  5890. +
  5891. + // Whether we should match subdomains of the host. This is true if the first
  5892. + // component of the pattern's host was "*".
  5893. + bool match_subdomains_;
  5894. +
  5895. + // The port.
  5896. + std::string port_;
  5897. +
  5898. + // The path to match. This is everything after the host of the URL, or
  5899. + // everything after the scheme in the case of file:// URLs.
  5900. + std::string path_;
  5901. +
  5902. + // The path with "?" and "\" characters escaped for use with the
  5903. + // MatchPattern() function.
  5904. + std::string path_escaped_;
  5905. +
  5906. + // A string representing this URLPattern.
  5907. + mutable std::string spec_;
  5908. +};
  5909. +
  5910. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5911. +
  5912. +typedef std::vector<URLPattern> URLPatternList;
  5913. +
  5914. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_H_
  5915. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5916. new file mode 100755
  5917. --- /dev/null
  5918. +++ b/components/user_scripts/common/url_pattern_set.cc
  5919. @@ -0,0 +1,335 @@
  5920. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5921. +// Use of this source code is governed by a BSD-style license that can be
  5922. +// found in the LICENSE file.
  5923. +
  5924. +#include "url_pattern_set.h"
  5925. +
  5926. +#include <iterator>
  5927. +#include <ostream>
  5928. +
  5929. +#include "base/containers/contains.h"
  5930. +#include "base/logging.h"
  5931. +#include "base/stl_util.h"
  5932. +#include "base/values.h"
  5933. +#include "error_utils.h"
  5934. +#include "url_pattern.h"
  5935. +#include "url/gurl.h"
  5936. +#include "url/origin.h"
  5937. +#include "url/url_constants.h"
  5938. +#include "user_scripts_features.h"
  5939. +
  5940. +namespace user_scripts {
  5941. +
  5942. +namespace {
  5943. +
  5944. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5945. +
  5946. +} // namespace
  5947. +
  5948. +// static
  5949. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5950. + const URLPatternSet& set2) {
  5951. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5952. + set1.patterns_, set2.patterns_));
  5953. +}
  5954. +
  5955. +// static
  5956. +URLPatternSet URLPatternSet::CreateIntersection(
  5957. + const URLPatternSet& set1,
  5958. + const URLPatternSet& set2,
  5959. + IntersectionBehavior intersection_behavior) {
  5960. + // Note: leverage return value optimization; always return the same object.
  5961. + URLPatternSet result;
  5962. +
  5963. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5964. + // String comparison just relies on STL set behavior, which looks at the
  5965. + // string representation.
  5966. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5967. + set1.patterns_, set2.patterns_));
  5968. + return result;
  5969. + }
  5970. +
  5971. + // Look for a semantic intersection.
  5972. +
  5973. + // Step 1: Iterate over each set. Find any patterns that are completely
  5974. + // contained by the other (thus being necessarily present in any intersection)
  5975. + // and add them, collecting the others in a set of unique items.
  5976. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5977. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5978. + // const, this should be safe.
  5979. + std::vector<const URLPattern*> unique_set1;
  5980. + for (const URLPattern& pattern : set1) {
  5981. + if (set2.ContainsPattern(pattern))
  5982. + result.patterns_.insert(pattern);
  5983. + else
  5984. + unique_set1.push_back(&pattern);
  5985. + }
  5986. + std::vector<const URLPattern*> unique_set2;
  5987. + for (const URLPattern& pattern : set2) {
  5988. + if (set1.ContainsPattern(pattern))
  5989. + result.patterns_.insert(pattern);
  5990. + else
  5991. + unique_set2.push_back(&pattern);
  5992. + }
  5993. +
  5994. + // If we're just looking for patterns contained by both, we're done.
  5995. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5996. + return result;
  5997. +
  5998. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5999. +
  6000. + // Step 2: Iterate over all the unique patterns and find the intersections
  6001. + // they have with the other patterns.
  6002. + for (const auto* pattern : unique_set1) {
  6003. + for (const auto* pattern2 : unique_set2) {
  6004. + absl::optional<URLPattern> intersection =
  6005. + pattern->CreateIntersection(*pattern2);
  6006. + if (intersection)
  6007. + result.patterns_.insert(std::move(*intersection));
  6008. + }
  6009. + }
  6010. +
  6011. + return result;
  6012. +}
  6013. +
  6014. +// static
  6015. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  6016. + const URLPatternSet& set2) {
  6017. + return URLPatternSet(
  6018. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  6019. +}
  6020. +
  6021. +// static
  6022. +URLPatternSet URLPatternSet::CreateUnion(
  6023. + const std::vector<URLPatternSet>& sets) {
  6024. + URLPatternSet result;
  6025. + if (sets.empty())
  6026. + return result;
  6027. +
  6028. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  6029. + //
  6030. + // Do the first merge step into a working set so that we don't mutate any of
  6031. + // the input.
  6032. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  6033. + // clean that up.
  6034. + std::vector<URLPatternSet> working;
  6035. + for (size_t i = 0; i < sets.size(); i += 2) {
  6036. + if (i + 1 < sets.size())
  6037. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  6038. + else
  6039. + working.push_back(sets[i].Clone());
  6040. + }
  6041. +
  6042. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  6043. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  6044. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  6045. + working[i].patterns_.swap(u.patterns_);
  6046. + }
  6047. + }
  6048. +
  6049. + result.patterns_.swap(working[0].patterns_);
  6050. + return result;
  6051. +}
  6052. +
  6053. +URLPatternSet::URLPatternSet() = default;
  6054. +
  6055. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  6056. +
  6057. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  6058. + : patterns_(patterns) {}
  6059. +
  6060. +URLPatternSet::~URLPatternSet() = default;
  6061. +
  6062. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  6063. +
  6064. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  6065. + return patterns_ == other.patterns_;
  6066. +}
  6067. +
  6068. +std::ostream& operator<<(std::ostream& out,
  6069. + const URLPatternSet& url_pattern_set) {
  6070. + out << "{ ";
  6071. +
  6072. + auto iter = url_pattern_set.patterns().cbegin();
  6073. + if (!url_pattern_set.patterns().empty()) {
  6074. + out << *iter;
  6075. + ++iter;
  6076. + }
  6077. +
  6078. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  6079. + out << ", " << *iter;
  6080. +
  6081. + if (!url_pattern_set.patterns().empty())
  6082. + out << " ";
  6083. +
  6084. + out << "}";
  6085. + return out;
  6086. +}
  6087. +
  6088. +URLPatternSet URLPatternSet::Clone() const {
  6089. + return URLPatternSet(patterns_);
  6090. +}
  6091. +
  6092. +bool URLPatternSet::is_empty() const {
  6093. + return patterns_.empty();
  6094. +}
  6095. +
  6096. +size_t URLPatternSet::size() const {
  6097. + return patterns_.size();
  6098. +}
  6099. +
  6100. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  6101. + return patterns_.insert(pattern).second;
  6102. +}
  6103. +
  6104. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  6105. + patterns_.insert(set.patterns().begin(),
  6106. + set.patterns().end());
  6107. +}
  6108. +
  6109. +void URLPatternSet::ClearPatterns() {
  6110. + patterns_.clear();
  6111. +}
  6112. +
  6113. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  6114. + if (origin.is_empty())
  6115. + return false;
  6116. + const url::Origin real_origin = url::Origin::Create(origin);
  6117. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(
  6118. + origin.DeprecatedGetOriginAsURL())));
  6119. + URLPattern origin_pattern(valid_schemes);
  6120. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  6121. + if (origin_pattern.Parse(origin.spec()) !=
  6122. + URLPattern::ParseResult::kSuccess) {
  6123. + return false;
  6124. + }
  6125. + origin_pattern.SetPath("/*");
  6126. + return AddPattern(origin_pattern);
  6127. +}
  6128. +
  6129. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  6130. + for (auto it = other.begin(); it != other.end(); ++it) {
  6131. + if (!ContainsPattern(*it))
  6132. + return false;
  6133. + }
  6134. +
  6135. + return true;
  6136. +}
  6137. +
  6138. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  6139. + for (auto it = begin(); it != end(); ++it) {
  6140. + if (it->Contains(pattern))
  6141. + return true;
  6142. + }
  6143. + return false;
  6144. +}
  6145. +
  6146. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  6147. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  6148. + ++pattern) {
  6149. + if (pattern->MatchesURL(url)) {
  6150. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6151. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  6152. +
  6153. + return true;
  6154. + }
  6155. + }
  6156. +
  6157. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6158. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  6159. +
  6160. + return false;
  6161. +}
  6162. +
  6163. +bool URLPatternSet::MatchesAllURLs() const {
  6164. + for (auto host = begin(); host != end(); ++host) {
  6165. + if (host->match_all_urls() ||
  6166. + (host->match_subdomains() && host->host().empty()))
  6167. + return true;
  6168. + }
  6169. + return false;
  6170. +}
  6171. +
  6172. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  6173. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  6174. + ++pattern) {
  6175. + if (pattern->MatchesSecurityOrigin(origin))
  6176. + return true;
  6177. + }
  6178. +
  6179. + return false;
  6180. +}
  6181. +
  6182. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  6183. + // Two extension extents overlap if there is any one URL that would match at
  6184. + // least one pattern in each of the extents.
  6185. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6186. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  6187. + ++j) {
  6188. + if (i->OverlapsWith(*j))
  6189. + return true;
  6190. + }
  6191. + }
  6192. +
  6193. + return false;
  6194. +}
  6195. +
  6196. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  6197. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  6198. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6199. + base::Value pattern_str_value(i->GetAsString());
  6200. + if (!base::Contains(value->GetList(), pattern_str_value))
  6201. + value->Append(std::move(pattern_str_value));
  6202. + }
  6203. + return value;
  6204. +}
  6205. +
  6206. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  6207. + int valid_schemes,
  6208. + bool allow_file_access,
  6209. + std::string* error) {
  6210. + ClearPatterns();
  6211. + for (size_t i = 0; i < patterns.size(); ++i) {
  6212. + URLPattern pattern(valid_schemes);
  6213. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  6214. + if (error) {
  6215. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  6216. + patterns[i]);
  6217. + } else {
  6218. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  6219. + }
  6220. + return false;
  6221. + }
  6222. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  6223. + pattern.SetValidSchemes(
  6224. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  6225. + }
  6226. + AddPattern(pattern);
  6227. + }
  6228. + return true;
  6229. +}
  6230. +
  6231. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  6232. + const {
  6233. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  6234. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6235. + value->push_back(i->GetAsString());
  6236. + }
  6237. + return value;
  6238. +}
  6239. +
  6240. +bool URLPatternSet::Populate(const base::ListValue& value,
  6241. + int valid_schemes,
  6242. + bool allow_file_access,
  6243. + std::string* error) {
  6244. + std::vector<std::string> patterns;
  6245. + for (const base::Value& pattern : value.GetList()) {
  6246. + const std::string* item = pattern.GetIfString();
  6247. + if (!item)
  6248. + return false;
  6249. + patterns.push_back(*item);
  6250. + }
  6251. + return Populate(patterns, valid_schemes, allow_file_access, error);
  6252. +}
  6253. +
  6254. +} // namespace extensions
  6255. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  6256. new file mode 100755
  6257. --- /dev/null
  6258. +++ b/components/user_scripts/common/url_pattern_set.h
  6259. @@ -0,0 +1,160 @@
  6260. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6261. +// Use of this source code is governed by a BSD-style license that can be
  6262. +// found in the LICENSE file.
  6263. +
  6264. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6265. +#define USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6266. +
  6267. +#include <stddef.h>
  6268. +
  6269. +#include <iosfwd>
  6270. +#include <memory>
  6271. +#include <set>
  6272. +
  6273. +#include "url_pattern.h"
  6274. +
  6275. +class GURL;
  6276. +
  6277. +namespace base {
  6278. +class ListValue;
  6279. +class Value;
  6280. +}
  6281. +
  6282. +namespace user_scripts {
  6283. +
  6284. +// Represents the set of URLs an extension uses for web content.
  6285. +class URLPatternSet {
  6286. + public:
  6287. + URLPatternSet(const URLPatternSet&) = delete;
  6288. + URLPatternSet& operator=(const URLPatternSet&) = delete;
  6289. + typedef std::set<URLPattern>::const_iterator const_iterator;
  6290. + typedef std::set<URLPattern>::iterator iterator;
  6291. +
  6292. + // Returns |set1| - |set2|.
  6293. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  6294. + const URLPatternSet& set2);
  6295. +
  6296. + enum class IntersectionBehavior {
  6297. + // For the following descriptions, consider the two URLPatternSets:
  6298. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  6299. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  6300. + // "*://chromium.org/*"}
  6301. +
  6302. + // Only includes patterns that are exactly in both sets. The intersection of
  6303. + // the two sets above is {"https://example.com/*"}, since that is the only
  6304. + // pattern that appears exactly in each.
  6305. + kStringComparison,
  6306. +
  6307. + // Includes patterns that are effectively contained by both sets. The
  6308. + // intersection of the two sets above is
  6309. + // {
  6310. + // "https://example.com/*" (contained exactly by each set)
  6311. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6312. + // subset of https://*.google.com/* in set 1)
  6313. + // }
  6314. + kPatternsContainedByBoth,
  6315. +
  6316. + // Includes patterns that are contained by both sets and creates new
  6317. + // patterns to represent the intersection of any others. The intersection of
  6318. + // the two sets above is
  6319. + // {
  6320. + // "https://example.com/*" (contained exactly by each set)
  6321. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6322. + // subset of https://*.google.com/* in set 1)
  6323. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  6324. + // *://chromium.org/*" in set 2).
  6325. + // }
  6326. + // Note that this is the most computationally expensive - potentially
  6327. + // O(n^2) - since it can require comparing each pattern in one set to every
  6328. + // pattern in the other set.
  6329. + kDetailed,
  6330. + };
  6331. +
  6332. + // Returns the intersection of |set1| and |set2| according to
  6333. + // |intersection_behavior|.
  6334. + static URLPatternSet CreateIntersection(
  6335. + const URLPatternSet& set1,
  6336. + const URLPatternSet& set2,
  6337. + IntersectionBehavior intersection_behavior);
  6338. +
  6339. + // Returns the union of |set1| and |set2|.
  6340. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  6341. + const URLPatternSet& set2);
  6342. +
  6343. + // Returns the union of all sets in |sets|.
  6344. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  6345. +
  6346. + URLPatternSet();
  6347. + URLPatternSet(URLPatternSet&& rhs);
  6348. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  6349. + ~URLPatternSet();
  6350. +
  6351. + URLPatternSet& operator=(URLPatternSet&& rhs);
  6352. + bool operator==(const URLPatternSet& rhs) const;
  6353. +
  6354. + bool is_empty() const;
  6355. + size_t size() const;
  6356. + const std::set<URLPattern>& patterns() const { return patterns_; }
  6357. + const_iterator begin() const { return patterns_.begin(); }
  6358. + const_iterator end() const { return patterns_.end(); }
  6359. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  6360. +
  6361. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  6362. + // constructor to avoid accidental/unnecessary copies.
  6363. + URLPatternSet Clone() const;
  6364. +
  6365. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  6366. + // false if the pattern was already in the set.
  6367. + bool AddPattern(const URLPattern& pattern);
  6368. +
  6369. + // Adds all patterns from |set| into this.
  6370. + void AddPatterns(const URLPatternSet& set);
  6371. +
  6372. + void ClearPatterns();
  6373. +
  6374. + // Adds a pattern based on |origin| to the set.
  6375. + bool AddOrigin(int valid_schemes, const GURL& origin);
  6376. +
  6377. + // Returns true if every URL that matches |set| is matched by this. In other
  6378. + // words, if every pattern in |set| is encompassed by a pattern in this.
  6379. + bool Contains(const URLPatternSet& set) const;
  6380. +
  6381. + // Returns true if any pattern in this set encompasses |pattern|.
  6382. + bool ContainsPattern(const URLPattern& pattern) const;
  6383. +
  6384. + // Test if the extent contains a URL.
  6385. + bool MatchesURL(const GURL& url) const;
  6386. +
  6387. + // Test if the extent matches all URLs (for example, <all_urls>).
  6388. + bool MatchesAllURLs() const;
  6389. +
  6390. + bool MatchesSecurityOrigin(const GURL& origin) const;
  6391. +
  6392. + // Returns true if there is a single URL that would be in two extents.
  6393. + bool OverlapsWith(const URLPatternSet& other) const;
  6394. +
  6395. + // Converts to and from Value for serialization to preferences.
  6396. + std::unique_ptr<base::ListValue> ToValue() const;
  6397. + bool Populate(const base::ListValue& value,
  6398. + int valid_schemes,
  6399. + bool allow_file_access,
  6400. + std::string* error);
  6401. +
  6402. + // Converts to and from a vector of strings.
  6403. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  6404. + bool Populate(const std::vector<std::string>& patterns,
  6405. + int valid_schemes,
  6406. + bool allow_file_access,
  6407. + std::string* error);
  6408. +
  6409. + private:
  6410. + // The list of URL patterns that comprise the extent.
  6411. + std::set<URLPattern> patterns_;
  6412. +};
  6413. +
  6414. +std::ostream& operator<<(std::ostream& out,
  6415. + const URLPatternSet& url_pattern_set);
  6416. +
  6417. +} // namespace extensions
  6418. +
  6419. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6420. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  6421. new file mode 100755
  6422. --- /dev/null
  6423. +++ b/components/user_scripts/common/user_script.cc
  6424. @@ -0,0 +1,329 @@
  6425. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6426. +// Use of this source code is governed by a BSD-style license that can be
  6427. +// found in the LICENSE file.
  6428. +
  6429. +#include "user_script.h"
  6430. +
  6431. +#include <stddef.h>
  6432. +#include <stdint.h>
  6433. +
  6434. +#include <memory>
  6435. +#include <utility>
  6436. +
  6437. +#include "base/atomic_sequence_num.h"
  6438. +#include "base/command_line.h"
  6439. +#include "base/pickle.h"
  6440. +#include "base/strings/pattern.h"
  6441. +#include "base/strings/string_util.h"
  6442. +#include "user_scripts_features.h"
  6443. +
  6444. +namespace {
  6445. +
  6446. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  6447. +// from multiple threads.
  6448. +base::AtomicSequenceNumber g_user_script_id_generator;
  6449. +
  6450. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  6451. + const GURL& url) {
  6452. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  6453. + if (base::MatchPattern(url.spec(), *glob))
  6454. + return true;
  6455. + }
  6456. +
  6457. + return false;
  6458. +}
  6459. +
  6460. +} // namespace
  6461. +
  6462. +namespace user_scripts {
  6463. +
  6464. +// The bitmask for valid user script injectable schemes used by URLPattern.
  6465. +enum {
  6466. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  6467. + URLPattern::SCHEME_HTTP |
  6468. + URLPattern::SCHEME_HTTPS
  6469. + //| URLPattern::SCHEME_FILE |
  6470. + //URLPattern::SCHEME_FTP
  6471. +};
  6472. +
  6473. +// static
  6474. +const char UserScript::kFileExtension[] = ".user.js";
  6475. +
  6476. +// static
  6477. +int UserScript::GenerateUserScriptID() {
  6478. + return g_user_script_id_generator.GetNext();
  6479. +}
  6480. +
  6481. +bool UserScript::IsURLUserScript(const GURL& url,
  6482. + const std::string& mime_type) {
  6483. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  6484. + base::CompareCase::INSENSITIVE_ASCII) &&
  6485. + mime_type != "text/html";
  6486. +}
  6487. +
  6488. +// static
  6489. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  6490. + if (canExecuteScriptEverywhere)
  6491. + return URLPattern::SCHEME_ALL;
  6492. + int valid_schemes = kValidUserScriptSchemes;
  6493. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  6494. + // switches::kExtensionsOnChromeURLs)) {
  6495. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  6496. + // }
  6497. + return valid_schemes;
  6498. +}
  6499. +
  6500. +UserScript::File::File(const base::FilePath& extension_root,
  6501. + const base::FilePath& relative_path,
  6502. + const GURL& url)
  6503. + : extension_root_(extension_root),
  6504. + relative_path_(relative_path),
  6505. + url_(url) {
  6506. +}
  6507. +
  6508. +UserScript::File::File() {}
  6509. +
  6510. +UserScript::File::File(const File& other)
  6511. + : extension_root_(other.extension_root_),
  6512. + relative_path_(other.relative_path_),
  6513. + url_(other.url_),
  6514. + external_content_(other.external_content_),
  6515. + content_(other.content_),
  6516. + key_(other.key_) {}
  6517. +
  6518. +UserScript::File::~File() {}
  6519. +
  6520. +UserScript::UserScript() = default;
  6521. +UserScript::~UserScript() = default;
  6522. +
  6523. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  6524. + url_set_.AddPattern(pattern);
  6525. +}
  6526. +
  6527. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  6528. + exclude_url_set_.AddPattern(pattern);
  6529. +}
  6530. +
  6531. +bool UserScript::MatchesURL(const GURL& url) const {
  6532. + // Since the injecton is also provided for native pages,
  6533. + // we must verify that the render process does not include
  6534. + // scripts in the schema that are not allowed
  6535. +
  6536. + // we allow only URLPattern::SCHEME_HTTP(S)
  6537. + URLPattern pattern(kValidUserScriptSchemes);
  6538. + pattern.Parse(url.spec());
  6539. + if (!pattern.IsValidScheme(pattern.scheme()))
  6540. + return false;
  6541. +
  6542. + if (!url_set_.is_empty()) {
  6543. + if (!url_set_.MatchesURL(url)) {
  6544. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6545. + LOG(INFO) << "UserScripts: No Match for url_set";
  6546. + return false;
  6547. + }
  6548. + }
  6549. +
  6550. + if (!exclude_url_set_.is_empty()) {
  6551. + if (exclude_url_set_.MatchesURL(url)) {
  6552. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6553. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  6554. + return false;
  6555. + }
  6556. + }
  6557. +
  6558. + if (!globs_.empty()) {
  6559. + if (!UrlMatchesGlobs(&globs_, url)) {
  6560. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6561. + LOG(INFO) << "UserScripts: No Match for globs";
  6562. + return false;
  6563. + }
  6564. + }
  6565. +
  6566. + if (!exclude_globs_.empty()) {
  6567. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  6568. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6569. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  6570. + return false;
  6571. + }
  6572. + }
  6573. +
  6574. + return true;
  6575. +}
  6576. +
  6577. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  6578. + bool is_subframe) const {
  6579. + if (is_subframe && !match_all_frames())
  6580. + return false;
  6581. +
  6582. + return MatchesURL(effective_document_url);
  6583. +}
  6584. +
  6585. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  6586. + pickle->WriteString(url_.spec());
  6587. + // Do not write path. It's not needed in the renderer.
  6588. + // Do not write content. It will be serialized by other means.
  6589. +}
  6590. +
  6591. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  6592. + base::PickleIterator* iter) {
  6593. + // Read the url from the pickle.
  6594. + std::string url;
  6595. + CHECK(iter->ReadString(&url));
  6596. + set_url(GURL(url));
  6597. +}
  6598. +
  6599. +void UserScript::Pickle(base::Pickle* pickle) const {
  6600. + // Write the simple types to the pickle.
  6601. + pickle->WriteInt(run_location());
  6602. + pickle->WriteInt(user_script_id_);
  6603. + pickle->WriteString(name_);
  6604. + pickle->WriteBool(emulate_greasemonkey());
  6605. + pickle->WriteBool(match_all_frames());
  6606. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  6607. + pickle->WriteBool(is_incognito_enabled());
  6608. +
  6609. + PickleHostID(pickle, host_id_);
  6610. + pickle->WriteInt(consumer_instance_type());
  6611. + PickleGlobs(pickle, globs_);
  6612. + PickleGlobs(pickle, exclude_globs_);
  6613. + PickleURLPatternSet(pickle, url_set_);
  6614. + PickleURLPatternSet(pickle, exclude_url_set_);
  6615. + PickleScripts(pickle, js_scripts_);
  6616. + PickleScripts(pickle, css_scripts_);
  6617. +}
  6618. +
  6619. +void UserScript::PickleGlobs(base::Pickle* pickle,
  6620. + const std::vector<std::string>& globs) const {
  6621. + pickle->WriteUInt32(globs.size());
  6622. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  6623. + pickle->WriteString(*glob);
  6624. + }
  6625. +}
  6626. +
  6627. +void UserScript::PickleHostID(base::Pickle* pickle,
  6628. + const HostID& host_id) const {
  6629. + pickle->WriteInt(host_id.type());
  6630. + pickle->WriteString(host_id.id());
  6631. +}
  6632. +
  6633. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  6634. + const URLPatternSet& pattern_list) const {
  6635. + pickle->WriteUInt32(pattern_list.patterns().size());
  6636. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  6637. + ++pattern) {
  6638. + pickle->WriteInt(pattern->valid_schemes());
  6639. + pickle->WriteString(pattern->GetAsString());
  6640. + }
  6641. +}
  6642. +
  6643. +void UserScript::PickleScripts(base::Pickle* pickle,
  6644. + const FileList& scripts) const {
  6645. + pickle->WriteUInt32(scripts.size());
  6646. + for (const std::unique_ptr<File>& file : scripts)
  6647. + file->Pickle(pickle);
  6648. +}
  6649. +
  6650. +void UserScript::Unpickle(const base::Pickle& pickle,
  6651. + base::PickleIterator* iter) {
  6652. + // Read the run location.
  6653. + int run_location = 0;
  6654. + CHECK(iter->ReadInt(&run_location));
  6655. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  6656. + run_location_ = static_cast<RunLocation>(run_location);
  6657. +
  6658. + CHECK(iter->ReadInt(&user_script_id_));
  6659. + CHECK(iter->ReadString(&name_));
  6660. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  6661. + CHECK(iter->ReadBool(&match_all_frames_));
  6662. + int match_origin_as_fallback_int = 0;
  6663. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  6664. + match_origin_as_fallback_ =
  6665. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  6666. + CHECK(iter->ReadBool(&incognito_enabled_));
  6667. +
  6668. + UnpickleHostID(pickle, iter, &host_id_);
  6669. +
  6670. + int consumer_instance_type = 0;
  6671. + CHECK(iter->ReadInt(&consumer_instance_type));
  6672. + consumer_instance_type_ =
  6673. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  6674. +
  6675. + UnpickleGlobs(pickle, iter, &globs_);
  6676. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  6677. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  6678. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  6679. + UnpickleScripts(pickle, iter, &js_scripts_);
  6680. + UnpickleScripts(pickle, iter, &css_scripts_);
  6681. +}
  6682. +
  6683. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  6684. + base::PickleIterator* iter,
  6685. + std::vector<std::string>* globs) {
  6686. + uint32_t num_globs = 0;
  6687. + CHECK(iter->ReadUInt32(&num_globs));
  6688. + globs->clear();
  6689. + for (uint32_t i = 0; i < num_globs; ++i) {
  6690. + std::string glob;
  6691. + CHECK(iter->ReadString(&glob));
  6692. + globs->push_back(glob);
  6693. + }
  6694. +}
  6695. +
  6696. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  6697. + base::PickleIterator* iter,
  6698. + HostID* host_id) {
  6699. + int type = 0;
  6700. + std::string id;
  6701. + CHECK(iter->ReadInt(&type));
  6702. + CHECK(iter->ReadString(&id));
  6703. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  6704. +}
  6705. +
  6706. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  6707. + base::PickleIterator* iter,
  6708. + URLPatternSet* pattern_list) {
  6709. + uint32_t num_patterns = 0;
  6710. + CHECK(iter->ReadUInt32(&num_patterns));
  6711. +
  6712. + pattern_list->ClearPatterns();
  6713. + for (uint32_t i = 0; i < num_patterns; ++i) {
  6714. + int valid_schemes;
  6715. + CHECK(iter->ReadInt(&valid_schemes));
  6716. +
  6717. + std::string pattern_str;
  6718. + CHECK(iter->ReadString(&pattern_str));
  6719. +
  6720. + URLPattern pattern(kValidUserScriptSchemes);
  6721. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  6722. + CHECK(URLPattern::ParseResult::kSuccess == result)
  6723. + << URLPattern::GetParseResultString(result) << " "
  6724. + << pattern_str.c_str();
  6725. +
  6726. + pattern.SetValidSchemes(valid_schemes);
  6727. + pattern_list->AddPattern(pattern);
  6728. + }
  6729. +}
  6730. +
  6731. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  6732. + base::PickleIterator* iter,
  6733. + FileList* scripts) {
  6734. + uint32_t num_files = 0;
  6735. + CHECK(iter->ReadUInt32(&num_files));
  6736. + scripts->clear();
  6737. + for (uint32_t i = 0; i < num_files; ++i) {
  6738. + std::unique_ptr<File> file(new File());
  6739. + file->Unpickle(pickle, iter);
  6740. + scripts->push_back(std::move(file));
  6741. + }
  6742. +}
  6743. +
  6744. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  6745. + : id(id), host_id(host_id) {}
  6746. +
  6747. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  6748. +
  6749. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  6750. + return a.id < b.id;
  6751. +}
  6752. +
  6753. +} // namespace extensions
  6754. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  6755. new file mode 100755
  6756. --- /dev/null
  6757. +++ b/components/user_scripts/common/user_script.h
  6758. @@ -0,0 +1,403 @@
  6759. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6760. +// Use of this source code is governed by a BSD-style license that can be
  6761. +// found in the LICENSE file.
  6762. +
  6763. +#ifndef USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6764. +#define USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6765. +
  6766. +#include <memory>
  6767. +#include <string>
  6768. +#include <vector>
  6769. +
  6770. +#include "base/files/file_path.h"
  6771. +#include "base/strings/string_piece.h"
  6772. +#include "script_constants.h"
  6773. +#include "host_id.h"
  6774. +#include "url_pattern.h"
  6775. +#include "url_pattern_set.h"
  6776. +#include "url/gurl.h"
  6777. +
  6778. +namespace base {
  6779. +class Pickle;
  6780. +class PickleIterator;
  6781. +}
  6782. +
  6783. +namespace user_scripts {
  6784. +
  6785. +// Represents a user script, either a standalone one, or one that is part of an
  6786. +// extension.
  6787. +class UserScript {
  6788. + public:
  6789. + UserScript(const UserScript&) = delete;
  6790. + UserScript& operator=(const UserScript&) = delete;
  6791. + // The file extension for standalone user scripts.
  6792. + static const char kFileExtension[];
  6793. +
  6794. + static int GenerateUserScriptID();
  6795. +
  6796. + // Check if a URL should be treated as a user script and converted to an
  6797. + // extension.
  6798. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  6799. +
  6800. + // Get the valid user script schemes for the current process. If
  6801. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6802. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6803. +
  6804. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6805. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6806. + // The type of injected script.
  6807. + enum InjectionType {
  6808. + // A content script specified in the extension's manifest.
  6809. + CONTENT_SCRIPT,
  6810. + // A script injected via, e.g. tabs.executeScript().
  6811. + //PROGRAMMATIC_SCRIPT
  6812. + };
  6813. + // The last type of injected script; used for enum verification in IPC.
  6814. + // Update this if you add more injected script types!
  6815. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6816. +
  6817. + // Locations that user scripts can be run inside the document.
  6818. + // The three run locations must strictly follow each other in both load order
  6819. + // (i.e., start *always* comes before end) and numerically, as we use
  6820. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6821. + enum RunLocation {
  6822. + UNDEFINED,
  6823. + DOCUMENT_START, // After the documentElement is created, but before
  6824. + // anything else happens.
  6825. + DOCUMENT_END, // After the entire document is parsed. Same as
  6826. + // DOMContentLoaded.
  6827. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6828. + // is "idle". Currently this uses the simple heuristic of:
  6829. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6830. + // particular injection point is guaranteed.
  6831. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6832. + // reasons, and was executed at a later time.
  6833. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6834. + // IPC in the browser process.
  6835. + RUN_LOCATION_LAST // Leave this as the last item.
  6836. + };
  6837. +
  6838. + // Holds script file info.
  6839. + class File {
  6840. + public:
  6841. + File(const base::FilePath& extension_root,
  6842. + const base::FilePath& relative_path,
  6843. + const GURL& url);
  6844. + File();
  6845. + File(const File& other);
  6846. + ~File();
  6847. +
  6848. + const base::FilePath& extension_root() const { return extension_root_; }
  6849. + const base::FilePath& relative_path() const { return relative_path_; }
  6850. +
  6851. + const GURL& url() const { return url_; }
  6852. + void set_url(const GURL& url) { url_ = url; }
  6853. +
  6854. + // If external_content_ is set returns it as content otherwise it returns
  6855. + // content_
  6856. + const base::StringPiece GetContent() const {
  6857. + if (external_content_.data())
  6858. + return external_content_;
  6859. + else
  6860. + return content_;
  6861. + }
  6862. + void set_external_content(const base::StringPiece& content) {
  6863. + external_content_ = content;
  6864. + }
  6865. + void set_content(const base::StringPiece& content) {
  6866. + content_.assign(content.begin(), content.end());
  6867. + }
  6868. +
  6869. + const std::string& key() const { return key_; }
  6870. + void set_key(const std::string& key) {
  6871. + key_ = key;
  6872. + }
  6873. +
  6874. + // Serialization support. The content and FilePath members will not be
  6875. + // serialized!
  6876. + void Pickle(base::Pickle* pickle) const;
  6877. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6878. +
  6879. + private:
  6880. + // Where the script file lives on the disk. We keep the path split so that
  6881. + // it can be localized at will.
  6882. + base::FilePath extension_root_;
  6883. + base::FilePath relative_path_;
  6884. +
  6885. + // The url to this script file.
  6886. + GURL url_;
  6887. +
  6888. + // The script content. It can be set to either loaded_content_ or
  6889. + // externally allocated string.
  6890. + base::StringPiece external_content_;
  6891. +
  6892. + // Set when the content is loaded by LoadContent
  6893. + std::string content_;
  6894. +
  6895. + std::string key_;
  6896. + };
  6897. +
  6898. + using FileList = std::vector<std::unique_ptr<File>>;
  6899. +
  6900. + // Type of a API consumer instance that user scripts will be injected on.
  6901. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6902. +
  6903. + // Constructor. Default the run location to document end, which is like
  6904. + // Greasemonkey and probably more useful for typical scripts.
  6905. + UserScript();
  6906. + ~UserScript();
  6907. +
  6908. + // Performs a copy of all fields except file contents.
  6909. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6910. +
  6911. + const std::string& name_space() const { return name_space_; }
  6912. + void set_name_space(const std::string& name_space) {
  6913. + name_space_ = name_space;
  6914. + }
  6915. +
  6916. + const std::string& name() const { return name_; }
  6917. + void set_name(const std::string& name) { name_ = name; }
  6918. +
  6919. + const std::string& version() const { return version_; }
  6920. + void set_version(const std::string& version) {
  6921. + version_ = version;
  6922. + }
  6923. +
  6924. + const std::string& key() const { return key_; }
  6925. + void set_key(const std::string& key) {
  6926. + key_ = key;
  6927. + }
  6928. +
  6929. + const std::string& file_path() const { return file_path_; }
  6930. + void set_file_path(const std::string& file_path) {
  6931. + file_path_ = file_path;
  6932. + }
  6933. +
  6934. + const std::string& url_source() const { return url_source_; }
  6935. + void set_url_source(const std::string& url_source) {
  6936. + url_source_ = url_source;
  6937. + }
  6938. +
  6939. + const std::string& description() const { return description_; }
  6940. + void set_description(const std::string& description) {
  6941. + description_ = description;
  6942. + }
  6943. +
  6944. + const std::string& parser_error() const { return parser_error_; }
  6945. + void set_parser_error(const std::string& parser_error) {
  6946. + parser_error_ = parser_error;
  6947. + }
  6948. +
  6949. + bool force_disabled() const { return force_disabled_; }
  6950. + void set_force_disabled() {
  6951. + force_disabled_ = true;
  6952. + }
  6953. +
  6954. + // The place in the document to run the script.
  6955. + RunLocation run_location() const { return run_location_; }
  6956. + void set_run_location(RunLocation location) { run_location_ = location; }
  6957. +
  6958. + // Whether to emulate greasemonkey when running this script.
  6959. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6960. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6961. +
  6962. + // Whether to match all frames, or only the top one.
  6963. + bool match_all_frames() const { return match_all_frames_; }
  6964. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6965. +
  6966. + // Whether to match the origin as a fallback if the URL cannot be used
  6967. + // directly.
  6968. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6969. + return match_origin_as_fallback_;
  6970. + }
  6971. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6972. + match_origin_as_fallback_ = val;
  6973. + }
  6974. +
  6975. + // The globs, if any, that determine which pages this script runs against.
  6976. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6977. + const std::vector<std::string>& globs() const { return globs_; }
  6978. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6979. + void clear_globs() { globs_.clear(); }
  6980. + const std::vector<std::string>& exclude_globs() const {
  6981. + return exclude_globs_;
  6982. + }
  6983. + void add_exclude_glob(const std::string& glob) {
  6984. + exclude_globs_.push_back(glob);
  6985. + }
  6986. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6987. +
  6988. + // The URLPatterns, if any, that determine which pages this script runs
  6989. + // against.
  6990. + const URLPatternSet& url_patterns() const { return url_set_; }
  6991. + void add_url_pattern(const URLPattern& pattern);
  6992. + const URLPatternSet& exclude_url_patterns() const {
  6993. + return exclude_url_set_;
  6994. + }
  6995. + void add_exclude_url_pattern(const URLPattern& pattern);
  6996. +
  6997. + // List of js scripts for this user script
  6998. + FileList& js_scripts() { return js_scripts_; }
  6999. + const FileList& js_scripts() const { return js_scripts_; }
  7000. +
  7001. + // List of css scripts for this user script
  7002. + FileList& css_scripts() { return css_scripts_; }
  7003. + const FileList& css_scripts() const { return css_scripts_; }
  7004. +
  7005. + const std::string& extension_id() const { return host_id_.id(); }
  7006. +
  7007. + const HostID& host_id() const { return host_id_; }
  7008. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  7009. +
  7010. + const ConsumerInstanceType& consumer_instance_type() const {
  7011. + return consumer_instance_type_;
  7012. + }
  7013. + void set_consumer_instance_type(
  7014. + const ConsumerInstanceType& consumer_instance_type) {
  7015. + consumer_instance_type_ = consumer_instance_type;
  7016. + }
  7017. +
  7018. + int id() const { return user_script_id_; }
  7019. + void set_id(int id) { user_script_id_ = id; }
  7020. +
  7021. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  7022. + // belong here. We should be able to determine this in the renderer/ where it
  7023. + // is used.
  7024. + bool is_incognito_enabled() const { return incognito_enabled_; }
  7025. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  7026. +
  7027. + // Returns true if the script should be applied to the specified URL, false
  7028. + // otherwise.
  7029. + bool MatchesURL(const GURL& url) const;
  7030. +
  7031. + // Returns true if the script should be applied to the given
  7032. + // |effective_document_url|. It is the caller's responsibility to calculate
  7033. + // |effective_document_url| based on match_origin_as_fallback().
  7034. + bool MatchesDocument(const GURL& effective_document_url,
  7035. + bool is_subframe) const;
  7036. +
  7037. + // Serializes the UserScript into a pickle. The content of the scripts and
  7038. + // paths to UserScript::Files will not be serialized!
  7039. + void Pickle(base::Pickle* pickle) const;
  7040. +
  7041. + // Deserializes the script from a pickle. Note that this always succeeds
  7042. + // because presumably we were the one that pickled it, and we did it
  7043. + // correctly.
  7044. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  7045. +
  7046. + private:
  7047. + // base::Pickle helper functions used to pickle the individual types of
  7048. + // components.
  7049. + void PickleGlobs(base::Pickle* pickle,
  7050. + const std::vector<std::string>& globs) const;
  7051. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  7052. + void PickleURLPatternSet(base::Pickle* pickle,
  7053. + const URLPatternSet& pattern_list) const;
  7054. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  7055. +
  7056. + // Unpickle helper functions used to unpickle individual types of components.
  7057. + void UnpickleGlobs(const base::Pickle& pickle,
  7058. + base::PickleIterator* iter,
  7059. + std::vector<std::string>* globs);
  7060. + void UnpickleHostID(const base::Pickle& pickle,
  7061. + base::PickleIterator* iter,
  7062. + HostID* host_id);
  7063. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  7064. + base::PickleIterator* iter,
  7065. + URLPatternSet* pattern_list);
  7066. + void UnpickleScripts(const base::Pickle& pickle,
  7067. + base::PickleIterator* iter,
  7068. + FileList* scripts);
  7069. +
  7070. + // The location to run the script inside the document.
  7071. + RunLocation run_location_ = DOCUMENT_IDLE;
  7072. +
  7073. + // The namespace of the script. This is used by Greasemonkey in the same way
  7074. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  7075. + std::string name_space_;
  7076. +
  7077. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  7078. + std::string name_;
  7079. +
  7080. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  7081. + std::string description_;
  7082. +
  7083. + // Parser error to show to user
  7084. + std::string parser_error_;
  7085. +
  7086. + // A version number of the script. Only used when parsing Greasemonkey-style
  7087. + // scripts.
  7088. + std::string version_;
  7089. +
  7090. + // Greasemonkey-style globs that determine pages to inject the script into.
  7091. + // These are only used with standalone scripts.
  7092. + std::vector<std::string> globs_;
  7093. + std::vector<std::string> exclude_globs_;
  7094. +
  7095. + // URLPatterns that determine pages to inject the script into. These are
  7096. + // only used with scripts that are part of extensions.
  7097. + URLPatternSet url_set_;
  7098. + URLPatternSet exclude_url_set_;
  7099. +
  7100. + // List of js scripts defined in content_scripts
  7101. + FileList js_scripts_;
  7102. +
  7103. + // List of css scripts defined in content_scripts
  7104. + FileList css_scripts_;
  7105. +
  7106. + // internal key of scripts
  7107. + std::string key_;
  7108. +
  7109. + std::string file_path_;
  7110. +
  7111. + // url source of script
  7112. + std::string url_source_;
  7113. +
  7114. + // The ID of the host this script is a part of. The |ID| of the
  7115. + // |host_id| can be empty if the script is a "standlone" user script.
  7116. + HostID host_id_;
  7117. +
  7118. + // The type of the consumer instance that the script will be injected.
  7119. + ConsumerInstanceType consumer_instance_type_ = TAB;
  7120. +
  7121. + // The globally-unique id associated with this user script. -1 indicates
  7122. + // "invalid".
  7123. + int user_script_id_ = -1;
  7124. +
  7125. + // Whether we should try to emulate Greasemonkey's APIs when running this
  7126. + // script.
  7127. + bool emulate_greasemonkey_ = false;
  7128. +
  7129. + // Whether the user script should run in all frames, or only just the top one.
  7130. + bool match_all_frames_ = false;
  7131. +
  7132. + // Whether the user script should run in frames whose initiator / precursor
  7133. + // origin matches a match pattern, if an appropriate URL cannot be found for
  7134. + // the frame for matching purposes, such as in the case of about:, data:, and
  7135. + // other schemes.
  7136. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  7137. + MatchOriginAsFallbackBehavior::kNever;
  7138. +
  7139. + // True if the script should be injected into an incognito tab.
  7140. + bool incognito_enabled_ = false;
  7141. +
  7142. + // Script cannot be enabled
  7143. + bool force_disabled_ = false;
  7144. +};
  7145. +
  7146. +// Information we need while removing scripts from a UserScriptLoader.
  7147. +struct UserScriptIDPair {
  7148. + UserScriptIDPair(int id, const HostID& host_id);
  7149. + explicit UserScriptIDPair(int id);
  7150. +
  7151. + int id;
  7152. + HostID host_id;
  7153. +};
  7154. +
  7155. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  7156. +
  7157. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  7158. +
  7159. +} // namespace extensions
  7160. +
  7161. +#endif // USERSCRIPTS_COMMON_USER_SCRIPT_H_
  7162. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  7163. new file mode 100644
  7164. --- /dev/null
  7165. +++ b/components/user_scripts/common/user_scripts_features.cc
  7166. @@ -0,0 +1,32 @@
  7167. +/*
  7168. + This file is part of Bromite.
  7169. +
  7170. + Bromite is free software: you can redistribute it and/or modify
  7171. + it under the terms of the GNU General Public License as published by
  7172. + the Free Software Foundation, either version 3 of the License, or
  7173. + (at your option) any later version.
  7174. +
  7175. + Bromite is distributed in the hope that it will be useful,
  7176. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7177. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7178. + GNU General Public License for more details.
  7179. +
  7180. + You should have received a copy of the GNU General Public License
  7181. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7182. +*/
  7183. +
  7184. +#include "user_scripts_features.h"
  7185. +
  7186. +#include "build/build_config.h"
  7187. +
  7188. +namespace user_scripts {
  7189. +
  7190. +namespace features {
  7191. +
  7192. +const base::Feature kEnableLoggingUserScripts =
  7193. + {"EnableLoggingUserScripts",
  7194. + base::FEATURE_DISABLED_BY_DEFAULT};
  7195. +
  7196. +}
  7197. +
  7198. +}
  7199. \ No newline at end of file
  7200. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  7201. new file mode 100644
  7202. --- /dev/null
  7203. +++ b/components/user_scripts/common/user_scripts_features.h
  7204. @@ -0,0 +1,34 @@
  7205. +/*
  7206. + This file is part of Bromite.
  7207. +
  7208. + Bromite is free software: you can redistribute it and/or modify
  7209. + it under the terms of the GNU General Public License as published by
  7210. + the Free Software Foundation, either version 3 of the License, or
  7211. + (at your option) any later version.
  7212. +
  7213. + Bromite is distributed in the hope that it will be useful,
  7214. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7215. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7216. + GNU General Public License for more details.
  7217. +
  7218. + You should have received a copy of the GNU General Public License
  7219. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7220. +*/
  7221. +
  7222. +#ifndef USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7223. +#define USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7224. +
  7225. +// This file defines all the base::FeatureList features for the Password Manager
  7226. +// module.
  7227. +
  7228. +#include "base/feature_list.h"
  7229. +
  7230. +namespace user_scripts {
  7231. +
  7232. +namespace features {
  7233. + extern const base::Feature kEnableLoggingUserScripts;
  7234. +}
  7235. +
  7236. +}
  7237. +
  7238. +#endif
  7239. \ No newline at end of file
  7240. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  7241. new file mode 100755
  7242. --- /dev/null
  7243. +++ b/components/user_scripts/common/view_type.cc
  7244. @@ -0,0 +1,39 @@
  7245. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7246. +// Use of this source code is governed by a BSD-style license that can be
  7247. +// found in the LICENSE file.
  7248. +
  7249. +#include "view_type.h"
  7250. +
  7251. +#include "base/strings/string_piece.h"
  7252. +
  7253. +namespace user_scripts {
  7254. +
  7255. +bool GetViewTypeFromString(const std::string& view_type,
  7256. + ViewType* view_type_out) {
  7257. + // TODO(devlin): This map doesn't contain the following values:
  7258. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  7259. + // - VIEW_TYPE_COMPONENT
  7260. + // - VIEW_TYPE_EXTENSION_GUEST
  7261. + // Why? Is it just because we don't expose those types to JS?
  7262. + static const struct {
  7263. + ViewType type;
  7264. + base::StringPiece name;
  7265. + } constexpr kTypeMap[] = {
  7266. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  7267. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  7268. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  7269. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  7270. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  7271. + };
  7272. +
  7273. + for (const auto& entry : kTypeMap) {
  7274. + if (entry.name == view_type) {
  7275. + *view_type_out = entry.type;
  7276. + return true;
  7277. + }
  7278. + }
  7279. +
  7280. + return false;
  7281. +}
  7282. +
  7283. +} // namespace extensions
  7284. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  7285. new file mode 100755
  7286. --- /dev/null
  7287. +++ b/components/user_scripts/common/view_type.h
  7288. @@ -0,0 +1,48 @@
  7289. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7290. +// Use of this source code is governed by a BSD-style license that can be
  7291. +// found in the LICENSE file.
  7292. +
  7293. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7294. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7295. +
  7296. +#include <string>
  7297. +
  7298. +namespace user_scripts {
  7299. +
  7300. +// Icky RTTI used by a few systems to distinguish the host type of a given
  7301. +// WebContents.
  7302. +//
  7303. +// Do not change or reuse the the entry values in this list as this is used in
  7304. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  7305. +//
  7306. +// TODO(aa): Remove this and teach those systems to keep track of their own
  7307. +// data.
  7308. +enum ViewType {
  7309. + VIEW_TYPE_INVALID = 0,
  7310. + // VIEW_TYPE_APP_WINDOW = 1,
  7311. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  7312. +
  7313. + // // For custom parts of Chrome if no other type applies.
  7314. + // VIEW_TYPE_COMPONENT = 3,
  7315. +
  7316. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  7317. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  7318. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  7319. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  7320. +
  7321. + // Panels were removed in https://crbug.com/571511.
  7322. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  7323. +
  7324. + VIEW_TYPE_TAB_CONTENTS = 9,
  7325. +
  7326. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  7327. +};
  7328. +
  7329. +// Matches the |view_type| to the corresponding ViewType, and populates
  7330. +// |view_type_out|. Returns true if a match is found.
  7331. +bool GetViewTypeFromString(const std::string& view_type,
  7332. + ViewType* view_type_out);
  7333. +
  7334. +} // namespace extensions
  7335. +
  7336. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7337. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  7338. new file mode 100755
  7339. --- /dev/null
  7340. +++ b/components/user_scripts/renderer/BUILD.gn
  7341. @@ -0,0 +1,67 @@
  7342. +# Copyright 2015 The Chromium Authors. All rights reserved.
  7343. +# Use of this source code is governed by a BSD-style license that can be
  7344. +# found in the LICENSE file.
  7345. +
  7346. +import("//tools/grit/grit_rule.gni")
  7347. +import("//tools/grit/repack.gni")
  7348. +
  7349. +group("user_scripts_resources") {
  7350. + public_deps = [
  7351. + ":user_scripts_renderer_resources",
  7352. + ]
  7353. +}
  7354. +
  7355. +grit("user_scripts_renderer_resources") {
  7356. + source = "resources/user_scripts_renderer_resources.grd"
  7357. + outputs = [
  7358. + "grit/user_scripts_renderer_resources.h",
  7359. + "user_scripts_renderer_resources.pak",
  7360. + ]
  7361. + grit_flags = [
  7362. + "-E",
  7363. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  7364. + ]
  7365. +}
  7366. +
  7367. +static_library("renderer") {
  7368. + sources = [
  7369. + "extension_frame_helper.cc",
  7370. + "extension_frame_helper.h",
  7371. + "injection_host.cc",
  7372. + "injection_host.h",
  7373. + "script_injection_manager.cc",
  7374. + "script_injection_manager.h",
  7375. + "script_injection_callback.cc",
  7376. + "script_injection_callback.h",
  7377. + "script_injection.cc",
  7378. + "script_injection.h",
  7379. + "script_injector.h",
  7380. + "script_context.cc",
  7381. + "script_context.h",
  7382. + "scripts_run_info.cc",
  7383. + "scripts_run_info.h",
  7384. + "user_script_injector.cc",
  7385. + "user_script_injector.h",
  7386. + "user_script_set_manager.cc",
  7387. + "user_script_set_manager.h",
  7388. + "user_script_set.cc",
  7389. + "user_script_set.h",
  7390. + "user_scripts_dispatcher.cc",
  7391. + "user_scripts_dispatcher.h",
  7392. + "user_scripts_renderer_client.cc",
  7393. + "user_scripts_renderer_client.h",
  7394. + "web_ui_injection_host.cc",
  7395. + "web_ui_injection_host.h",
  7396. + ]
  7397. +
  7398. + deps = [
  7399. + ":user_scripts_resources",
  7400. + "//base",
  7401. + "//content/public/common",
  7402. + "//content/public/renderer",
  7403. + "//components/user_scripts/common",
  7404. + "//mojo/public/cpp/bindings",
  7405. + "//third_party/blink/public:blink_headers",
  7406. + "//v8",
  7407. + ]
  7408. +}
  7409. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  7410. new file mode 100755
  7411. --- /dev/null
  7412. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  7413. @@ -0,0 +1,96 @@
  7414. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7415. +// Use of this source code is governed by a BSD-style license that can be
  7416. +// found in the LICENSE file.
  7417. +
  7418. +#include "extension_frame_helper.h"
  7419. +
  7420. +#include <set>
  7421. +
  7422. +#include "base/metrics/histogram_macros.h"
  7423. +#include "base/strings/string_util.h"
  7424. +#include "base/timer/elapsed_timer.h"
  7425. +#include "content/public/renderer/render_frame.h"
  7426. +#include "content/public/renderer/render_view.h"
  7427. +#include "../common/constants.h"
  7428. +#include "third_party/blink/public/platform/web_security_origin.h"
  7429. +#include "third_party/blink/public/web/web_console_message.h"
  7430. +#include "third_party/blink/public/web/web_document.h"
  7431. +#include "third_party/blink/public/web/web_document_loader.h"
  7432. +#include "third_party/blink/public/web/web_local_frame.h"
  7433. +#include "third_party/blink/public/web/web_settings.h"
  7434. +#include "third_party/blink/public/web/web_view.h"
  7435. +
  7436. +namespace user_scripts {
  7437. +
  7438. +namespace {
  7439. +
  7440. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  7441. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  7442. +
  7443. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  7444. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  7445. +void RunCallbacksWhileFrameIsValid(
  7446. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  7447. + std::vector<base::OnceClosure>* callbacks_to_be_run_and_cleared) {
  7448. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  7449. + // callbacks that are added during the iteration.
  7450. + std::vector<base::OnceClosure> callbacks;
  7451. + callbacks_to_be_run_and_cleared->swap(callbacks);
  7452. + for (auto& callback : callbacks) {
  7453. + std::move(callback).Run();
  7454. + if (!frame_helper.get())
  7455. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  7456. + }
  7457. +}
  7458. +
  7459. +} // namespace
  7460. +
  7461. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  7462. + : content::RenderFrameObserver(render_frame),
  7463. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  7464. + tab_id_(-1) {
  7465. + g_frame_helpers.Get().insert(this);
  7466. +}
  7467. +
  7468. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  7469. + g_frame_helpers.Get().erase(this);
  7470. +}
  7471. +
  7472. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  7473. + base::OnceClosure callback) {
  7474. + document_element_created_callbacks_.push_back(std::move(callback));
  7475. +}
  7476. +
  7477. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  7478. + base::OnceClosure callback) {
  7479. + document_load_finished_callbacks_.push_back(std::move(callback));
  7480. +}
  7481. +
  7482. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  7483. + base::OnceClosure callback) {
  7484. + document_idle_callbacks_.push_back(std::move(callback));
  7485. +}
  7486. +
  7487. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  7488. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7489. + &document_element_created_callbacks_);
  7490. + // |this| might be dead by now.
  7491. +}
  7492. +
  7493. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  7494. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7495. + &document_load_finished_callbacks_);
  7496. + // |this| might be dead by now.
  7497. +}
  7498. +
  7499. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  7500. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7501. + &document_idle_callbacks_);
  7502. + // |this| might be dead by now.
  7503. +}
  7504. +
  7505. +void ExtensionFrameHelper::OnDestruct() {
  7506. + delete this;
  7507. +}
  7508. +
  7509. +} // namespace user_scripts
  7510. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  7511. new file mode 100755
  7512. --- /dev/null
  7513. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  7514. @@ -0,0 +1,91 @@
  7515. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7516. +// Use of this source code is governed by a BSD-style license that can be
  7517. +// found in the LICENSE file.
  7518. +
  7519. +#ifndef USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7520. +#define USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7521. +
  7522. +#include <string>
  7523. +#include <vector>
  7524. +
  7525. +#include "base/callback_forward.h"
  7526. +#include "base/memory/weak_ptr.h"
  7527. +#include "content/public/renderer/render_frame_observer.h"
  7528. +#include "content/public/renderer/render_frame_observer_tracker.h"
  7529. +#include "../common/view_type.h"
  7530. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  7531. +#include "v8/include/v8.h"
  7532. +
  7533. +struct ExtensionMsg_ExternalConnectionInfo;
  7534. +struct ExtensionMsg_TabConnectionInfo;
  7535. +
  7536. +namespace base {
  7537. +class ListValue;
  7538. +}
  7539. +
  7540. +namespace user_scripts {
  7541. +
  7542. +class Dispatcher;
  7543. +struct Message;
  7544. +struct PortId;
  7545. +class ScriptContext;
  7546. +
  7547. +// RenderFrame-level plumbing for extension features.
  7548. +class ExtensionFrameHelper
  7549. + : public content::RenderFrameObserver,
  7550. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  7551. + public:
  7552. + ExtensionFrameHelper(const ExtensionFrameHelper&) = delete;
  7553. + ExtensionFrameHelper& operator=(const ExtensionFrameHelper&) = delete;
  7554. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  7555. + Dispatcher* extension_dispatcher*/);
  7556. + ~ExtensionFrameHelper() override;
  7557. +
  7558. + int tab_id() const { return tab_id_; }
  7559. +
  7560. + // Called when the document element has been inserted in this frame. This
  7561. + // method may invoke untrusted JavaScript code that invalidate the frame and
  7562. + // this ExtensionFrameHelper.
  7563. + void RunScriptsAtDocumentStart();
  7564. +
  7565. + // Called after the DOMContentLoaded event has fired.
  7566. + void RunScriptsAtDocumentEnd();
  7567. +
  7568. + // Called before the window.onload event is fired.
  7569. + void RunScriptsAtDocumentIdle();
  7570. +
  7571. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  7572. + // notification. Only call this when you are certain that there will be such a
  7573. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  7574. + // Otherwise the callback is never invoked, or invoked for a document that you
  7575. + // were not expecting.
  7576. + void ScheduleAtDocumentStart(base::OnceClosure callback);
  7577. +
  7578. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  7579. + void ScheduleAtDocumentEnd(base::OnceClosure callback);
  7580. +
  7581. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  7582. + void ScheduleAtDocumentIdle(base::OnceClosure callback);
  7583. +
  7584. + private:
  7585. +
  7586. + void OnDestruct() override;
  7587. +
  7588. + // The id of the tab the render frame is attached to.
  7589. + int tab_id_;
  7590. +
  7591. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  7592. + std::vector<base::OnceClosure> document_element_created_callbacks_;
  7593. +
  7594. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  7595. + std::vector<base::OnceClosure> document_load_finished_callbacks_;
  7596. +
  7597. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  7598. + std::vector<base::OnceClosure> document_idle_callbacks_;
  7599. +
  7600. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  7601. +};
  7602. +
  7603. +} // namespace extensions
  7604. +
  7605. +#endif // USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7606. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  7607. new file mode 100755
  7608. --- /dev/null
  7609. +++ b/components/user_scripts/renderer/injection_host.cc
  7610. @@ -0,0 +1,12 @@
  7611. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7612. +// Use of this source code is governed by a BSD-style license that can be
  7613. +// found in the LICENSE file.
  7614. +
  7615. +#include "injection_host.h"
  7616. +
  7617. +InjectionHost::InjectionHost(const HostID& host_id) :
  7618. + id_(host_id) {
  7619. +}
  7620. +
  7621. +InjectionHost::~InjectionHost() {
  7622. +}
  7623. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  7624. new file mode 100755
  7625. --- /dev/null
  7626. +++ b/components/user_scripts/renderer/injection_host.h
  7627. @@ -0,0 +1,41 @@
  7628. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7629. +// Use of this source code is governed by a BSD-style license that can be
  7630. +// found in the LICENSE file.
  7631. +
  7632. +#ifndef USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7633. +#define USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7634. +
  7635. +#include "../common/host_id.h"
  7636. +#include "url/gurl.h"
  7637. +
  7638. +namespace content {
  7639. +class RenderFrame;
  7640. +}
  7641. +
  7642. +// An interface for all kinds of hosts who own user scripts.
  7643. +class InjectionHost {
  7644. + public:
  7645. + InjectionHost(const InjectionHost&) = delete;
  7646. + InjectionHost& operator=(const InjectionHost&) = delete;
  7647. + InjectionHost(const HostID& host_id);
  7648. + virtual ~InjectionHost();
  7649. +
  7650. + // Returns the CSP to be used for the isolated world. Currently this only
  7651. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  7652. + // bypassed.
  7653. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  7654. +
  7655. + // The base url for the host.
  7656. + virtual const GURL& url() const = 0;
  7657. +
  7658. + // The human-readable name of the host.
  7659. + virtual const std::string& name() const = 0;
  7660. +
  7661. + const HostID& id() const { return id_; }
  7662. +
  7663. + private:
  7664. + // The ID of the host.
  7665. + HostID id_;
  7666. +};
  7667. +
  7668. +#endif // USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7669. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7670. new file mode 100755
  7671. --- /dev/null
  7672. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7673. @@ -0,0 +1,82 @@
  7674. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7675. +// Use of this source code is governed by a BSD-style license that can be
  7676. +// found in the LICENSE file.
  7677. +
  7678. +// -----------------------------------------------------------------------------
  7679. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  7680. +// have your change take effect.
  7681. +// -----------------------------------------------------------------------------
  7682. +
  7683. +// Partial implementation of the Greasemonkey API, see:
  7684. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  7685. +
  7686. +function GM_addStyle(css) {
  7687. + var parent = document.getElementsByTagName("head")[0];
  7688. + if (!parent) {
  7689. + parent = document.documentElement;
  7690. + }
  7691. + var style = document.createElement("style");
  7692. + style.type = "text/css";
  7693. + var textNode = document.createTextNode(css);
  7694. + style.appendChild(textNode);
  7695. + parent.appendChild(style);
  7696. +}
  7697. +
  7698. +function GM_xmlhttpRequest(details) {
  7699. + function setupEvent(xhr, url, eventName, callback) {
  7700. + xhr[eventName] = function () {
  7701. + var isComplete = xhr.readyState == 4;
  7702. + var responseState = {
  7703. + responseText: xhr.responseText,
  7704. + readyState: xhr.readyState,
  7705. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  7706. + status: isComplete ? xhr.status : 0,
  7707. + statusText: isComplete ? xhr.statusText : "",
  7708. + finalUrl: isComplete ? url : ""
  7709. + };
  7710. + callback(responseState);
  7711. + };
  7712. + }
  7713. +
  7714. + var xhr = new XMLHttpRequest();
  7715. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  7716. + for (var i = 0; i < eventNames.length; i++ ) {
  7717. + var eventName = eventNames[i];
  7718. + if (eventName in details) {
  7719. + setupEvent(xhr, details.url, eventName, details[eventName]);
  7720. + }
  7721. + }
  7722. +
  7723. + xhr.open(details.method, details.url);
  7724. +
  7725. + if (details.overrideMimeType) {
  7726. + xhr.overrideMimeType(details.overrideMimeType);
  7727. + }
  7728. + if (details.headers) {
  7729. + for (var header in details.headers) {
  7730. + xhr.setRequestHeader(header, details.headers[header]);
  7731. + }
  7732. + }
  7733. + xhr.send(details.data ? details.data : null);
  7734. +}
  7735. +
  7736. +function GM_openInTab(url) {
  7737. + window.open(url, "");
  7738. +}
  7739. +
  7740. +function GM_log(message) {
  7741. + window.console.log(message);
  7742. +}
  7743. +
  7744. +(function() {
  7745. + function generateGreasemonkeyStub(name) {
  7746. + return function() {
  7747. + console.log("%s is not supported.", name);
  7748. + };
  7749. + }
  7750. +
  7751. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  7752. + for (var i = 0, api; api = apis[i]; i++) {
  7753. + window[api] = generateGreasemonkeyStub(api);
  7754. + }
  7755. +})();
  7756. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7757. new file mode 100755
  7758. --- /dev/null
  7759. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7760. @@ -0,0 +1,14 @@
  7761. +<?xml version="1.0" encoding="UTF-8"?>
  7762. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  7763. + <outputs>
  7764. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  7765. + <emit emit_type='prepend'></emit>
  7766. + </output>
  7767. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  7768. + </outputs>
  7769. + <release seq="1">
  7770. + <includes>
  7771. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  7772. + </includes>
  7773. + </release>
  7774. +</grit>
  7775. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  7776. new file mode 100755
  7777. --- /dev/null
  7778. +++ b/components/user_scripts/renderer/script_context.cc
  7779. @@ -0,0 +1,215 @@
  7780. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7781. +// Use of this source code is governed by a BSD-style license that can be
  7782. +// found in the LICENSE file.
  7783. +
  7784. +#include "script_context.h"
  7785. +
  7786. +#include "base/command_line.h"
  7787. +#include "base/containers/flat_set.h"
  7788. +#include "base/containers/contains.h"
  7789. +#include "base/logging.h"
  7790. +#include "base/no_destructor.h"
  7791. +#include "base/stl_util.h"
  7792. +#include "base/strings/string_util.h"
  7793. +#include "base/strings/stringprintf.h"
  7794. +#include "base/values.h"
  7795. +#include "content/public/common/content_switches.h"
  7796. +#include "content/public/common/url_constants.h"
  7797. +#include "content/public/renderer/render_frame.h"
  7798. +#include "../common/constants.h"
  7799. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  7800. +#include "third_party/blink/public/platform/web_security_origin.h"
  7801. +#include "third_party/blink/public/web/web_document.h"
  7802. +#include "third_party/blink/public/web/web_document_loader.h"
  7803. +#include "third_party/blink/public/web/web_local_frame.h"
  7804. +#include "third_party/blink/public/web/web_navigation_params.h"
  7805. +#include "v8/include/v8.h"
  7806. +
  7807. +namespace user_scripts {
  7808. +
  7809. +namespace {
  7810. +
  7811. +GURL GetEffectiveDocumentURL(
  7812. + blink::WebLocalFrame* frame,
  7813. + const GURL& document_url,
  7814. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  7815. + bool allow_inaccessible_parents) {
  7816. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  7817. + switch (match_origin_as_fallback) {
  7818. + case MatchOriginAsFallbackBehavior::kNever:
  7819. + return false;
  7820. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  7821. + return document_url.SchemeIs(url::kAboutScheme);
  7822. + case MatchOriginAsFallbackBehavior::kAlways:
  7823. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  7824. + return document_url.SchemeIs(url::kAboutScheme) ||
  7825. + document_url.SchemeIs(url::kDataScheme);
  7826. + }
  7827. +
  7828. + NOTREACHED();
  7829. + };
  7830. +
  7831. + // If we don't need to consider the origin, we're done.
  7832. + if (!should_consider_origin())
  7833. + return document_url;
  7834. +
  7835. + // Get the "security origin" for the frame. For about: frames, this is the
  7836. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7837. + // https://example.com will have the security origin of https://example.com.
  7838. + // Other frames, like data: frames, will have an opaque origin. For these,
  7839. + // we can get the precursor origin.
  7840. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7841. + const url::Origin frame_origin = web_frame_origin;
  7842. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7843. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7844. +
  7845. + // When there's no valid tuple (which can happen in the case of e.g. a
  7846. + // browser-initiated navigation to an opaque URL), there's no origin to
  7847. + // fallback to. Bail.
  7848. + if (!tuple_or_precursor_tuple.IsValid())
  7849. + return document_url;
  7850. +
  7851. + const url::Origin origin_or_precursor_origin =
  7852. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7853. +
  7854. + if (!allow_inaccessible_parents &&
  7855. + !web_frame_origin.CanAccess(
  7856. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7857. + // The frame can't access its precursor. Bail.
  7858. + return document_url;
  7859. + }
  7860. +
  7861. + // Looks like the initiator origin is an appropriate fallback!
  7862. +
  7863. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7864. + // The easy case! We use the origin directly. We're done.
  7865. + return origin_or_precursor_origin.GetURL();
  7866. + }
  7867. +
  7868. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7869. + match_origin_as_fallback);
  7870. +
  7871. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7872. + // match patterns that are associated with paths as well, not just origins.
  7873. + // For instance, if an extension wants to run on google.com/maps/* with
  7874. + // match_about_blank true, then it should run on about:-scheme frames created
  7875. + // by google.com/maps, but not about:-scheme frames created by google.com
  7876. + // (which is what the precursor tuple origin would be).
  7877. +
  7878. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7879. + // with the same origin as the precursor and return its URL.
  7880. + // Note: This can return the incorrect result, e.g. if a parent frame
  7881. + // navigates a grandchild frame.
  7882. + blink::WebFrame* parent = frame;
  7883. + GURL parent_url;
  7884. + blink::WebDocument parent_document;
  7885. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7886. + do {
  7887. + already_visited_frames.insert(parent);
  7888. + if (parent->Parent())
  7889. + parent = parent->Parent();
  7890. + else
  7891. + parent = parent->Opener();
  7892. +
  7893. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7894. + // https://crbug.com/883526.
  7895. + if (base::Contains(already_visited_frames, parent))
  7896. + return document_url;
  7897. +
  7898. + parent_document = parent && parent->IsWebLocalFrame()
  7899. + ? parent->ToWebLocalFrame()->GetDocument()
  7900. + : blink::WebDocument();
  7901. +
  7902. + // We reached the end of the ancestral chain without finding a valid parent,
  7903. + // or found a remote web frame (in which case, it's a different origin).
  7904. + // Bail and use the original URL.
  7905. + if (parent_document.IsNull())
  7906. + return document_url;
  7907. +
  7908. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7909. + url::Origin(parent->GetSecurityOrigin())
  7910. + .GetTupleOrPrecursorTupleIfOpaque();
  7911. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7912. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7913. + // The parent has a different tuple origin than frame; this could happen
  7914. + // in edge cases where a parent navigates an iframe or popup of a child
  7915. + // frame at a different origin. [1] In this case, bail, since we can't
  7916. + // find a full URL (i.e., one including the path) with the same security
  7917. + // origin to use for the frame in question.
  7918. + // [1] Consider a frame tree like:
  7919. + // <html> <!--example.com-->
  7920. + // <iframe id="a" src="a.com">
  7921. + // <iframe id="b" src="b.com"></iframe>
  7922. + // </iframe>
  7923. + // </html>
  7924. + // Frame "a" is cross-origin from the top-level frame, and so the
  7925. + // example.com top-level frame can't directly access frame "b". However,
  7926. + // it can navigate it through
  7927. + // window.frames[0].frames[0].location.href = 'about:blank';
  7928. + // In that case, the precursor origin tuple origin of frame "b" would be
  7929. + // example.com, but the parent tuple origin is a.com.
  7930. + // Note that usually, this would have bailed earlier with a remote frame,
  7931. + // but it may not if we're at the process limit.
  7932. + return document_url;
  7933. + }
  7934. +
  7935. + parent_url = GURL(parent_document.Url());
  7936. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7937. +
  7938. + DCHECK(!parent_url.is_empty());
  7939. + DCHECK(!parent_document.IsNull());
  7940. +
  7941. + // We should know that the frame can access the parent document (unless we
  7942. + // explicitly allow it not to), since it has the same tuple origin as the
  7943. + // frame, and we checked the frame access above.
  7944. + DCHECK(allow_inaccessible_parents ||
  7945. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7946. + return parent_url;
  7947. +}
  7948. +
  7949. +using FrameToDocumentLoader =
  7950. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7951. +
  7952. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7953. + static base::NoDestructor<FrameToDocumentLoader> map;
  7954. + return *map;
  7955. +}
  7956. +
  7957. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7958. + const blink::WebLocalFrame* frame) {
  7959. + auto& map = FrameDocumentLoaderMap();
  7960. + auto it = map.find(frame);
  7961. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7962. +}
  7963. +
  7964. +} // namespace
  7965. +
  7966. +// static
  7967. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7968. + const blink::WebLocalFrame* frame) {
  7969. + // Normally we would use frame->document().url() to determine the document's
  7970. + // URL, but to decide whether to inject a content script, we use the URL from
  7971. + // the data source. This "quirk" helps prevents content scripts from
  7972. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7973. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7974. + // changes to match the parent document after Gmail document.writes into
  7975. + // it to create the editor.
  7976. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7977. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7978. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7979. +}
  7980. +
  7981. +// static
  7982. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7983. + blink::WebLocalFrame* frame,
  7984. + const GURL& document_url,
  7985. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7986. + // We explicitly allow inaccessible parents here. Extensions should still be
  7987. + // able to inject into a sandboxed iframe if it has access to the embedding
  7988. + // origin.
  7989. + constexpr bool allow_inaccessible_parents = true;
  7990. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7991. + allow_inaccessible_parents);
  7992. +}
  7993. +
  7994. +} // namespace extensions
  7995. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7996. new file mode 100755
  7997. --- /dev/null
  7998. +++ b/components/user_scripts/renderer/script_context.h
  7999. @@ -0,0 +1,69 @@
  8000. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8001. +// Use of this source code is governed by a BSD-style license that can be
  8002. +// found in the LICENSE file.
  8003. +
  8004. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  8005. +#define USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  8006. +
  8007. +#include <memory>
  8008. +#include <string>
  8009. +#include <utility>
  8010. +#include <vector>
  8011. +
  8012. +#include "base/callback.h"
  8013. +#include "base/compiler_specific.h"
  8014. +#include "base/threading/thread_checker.h"
  8015. +#include "base/unguessable_token.h"
  8016. +#include "../common/script_constants.h"
  8017. +#include "script_injection_callback.h"
  8018. +#include "url/gurl.h"
  8019. +#include "v8/include/v8.h"
  8020. +
  8021. +namespace blink {
  8022. +class WebDocumentLoader;
  8023. +class WebLocalFrame;
  8024. +}
  8025. +
  8026. +namespace content {
  8027. +class RenderFrame;
  8028. +}
  8029. +
  8030. +namespace user_scripts {
  8031. +
  8032. +// Extensions wrapper for a v8::Context.
  8033. +//
  8034. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  8035. +// destroyed that thread.
  8036. +//
  8037. +// Note that ScriptContexts bound to worker threads will not have the full
  8038. +// functionality as those bound to the main RenderThread.
  8039. +class ScriptContext {
  8040. + public:
  8041. + ScriptContext(const ScriptContext&) = delete;
  8042. + ScriptContext& operator=(const ScriptContext&) = delete;
  8043. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  8044. + // vaguely ScriptContext related, there's enough here that they probably
  8045. + // warrant another class or utility file.
  8046. +
  8047. + // Utility to get the URL we will match against for a frame. If the frame has
  8048. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  8049. + // The returned URL may be invalid.
  8050. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  8051. +
  8052. + // Used to determine the "effective" URL for extension script injection.
  8053. + // If |document_url| is an about: or data: URL, returns the URL of the first
  8054. + // frame without an about: or data: URL that matches the initiator origin.
  8055. + // This may not be the immediate parent. Returns |document_url| if it is not
  8056. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  8057. + // or if a suitable parent cannot be found.
  8058. + // Considers parent contexts that cannot be accessed (as is the case for
  8059. + // sandboxed frames).
  8060. + static GURL GetEffectiveDocumentURLForInjection(
  8061. + blink::WebLocalFrame* frame,
  8062. + const GURL& document_url,
  8063. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  8064. +};
  8065. +
  8066. +} // namespace extensions
  8067. +
  8068. +#endif // USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  8069. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  8070. new file mode 100755
  8071. --- /dev/null
  8072. +++ b/components/user_scripts/renderer/script_injection.cc
  8073. @@ -0,0 +1,343 @@
  8074. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8075. +// Use of this source code is governed by a BSD-style license that can be
  8076. +// found in the LICENSE file.
  8077. +
  8078. +#include "script_injection.h"
  8079. +
  8080. +#include <map>
  8081. +#include <utility>
  8082. +
  8083. +#include "base/bind.h"
  8084. +#include "base/feature_list.h"
  8085. +#include "base/lazy_instance.h"
  8086. +#include "base/metrics/histogram_macros.h"
  8087. +#include "base/timer/elapsed_timer.h"
  8088. +#include "base/values.h"
  8089. +#include "base/logging.h"
  8090. +#include "content/public/renderer/render_frame.h"
  8091. +#include "content/public/renderer/render_frame_observer.h"
  8092. +#include "content/public/renderer/v8_value_converter.h"
  8093. +#include "../common/host_id.h"
  8094. +#include "script_injection_callback.h"
  8095. +#include "scripts_run_info.h"
  8096. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  8097. +#include "third_party/blink/public/platform/web_security_origin.h"
  8098. +#include "third_party/blink/public/platform/web_string.h"
  8099. +#include "third_party/blink/public/web/web_document.h"
  8100. +#include "third_party/blink/public/web/web_local_frame.h"
  8101. +#include "third_party/blink/public/web/web_script_source.h"
  8102. +#include "url/gurl.h"
  8103. +
  8104. +namespace user_scripts {
  8105. +
  8106. +namespace {
  8107. +
  8108. +using IsolatedWorldMap = std::map<std::string, int>;
  8109. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  8110. + LAZY_INSTANCE_INITIALIZER;
  8111. +
  8112. +const int64_t kInvalidRequestId = -1;
  8113. +
  8114. +// Gets the isolated world ID to use for the given |injection_host|. If no
  8115. +// isolated world has been created for that |injection_host| one will be created
  8116. +// and initialized.
  8117. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  8118. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  8119. +
  8120. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8121. +
  8122. + int id = 0;
  8123. + const std::string& key = injection_host->id().id();
  8124. + auto iter = isolated_worlds.find(key);
  8125. + if (iter != isolated_worlds.end()) {
  8126. + id = iter->second;
  8127. + } else {
  8128. + id = g_next_isolated_world_id++;
  8129. + // This map will tend to pile up over time, but realistically, you're never
  8130. + // going to have enough injection hosts for it to matter.
  8131. + isolated_worlds[key] = id;
  8132. + }
  8133. +
  8134. + blink::WebIsolatedWorldInfo info;
  8135. + info.security_origin =
  8136. + blink::WebSecurityOrigin::Create(injection_host->url());
  8137. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  8138. + info.stable_id = blink::WebString::FromUTF8(key);
  8139. +
  8140. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  8141. + if (csp)
  8142. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  8143. +
  8144. + // Even though there may be an existing world for this |injection_host|'s key,
  8145. + // the properties may have changed (e.g. due to an extension update).
  8146. + // Overwrite any existing entries.
  8147. + blink::SetIsolatedWorldInfo(id, info);
  8148. +
  8149. + return id;
  8150. +}
  8151. +
  8152. +// This class manages its own lifetime.
  8153. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  8154. + public:
  8155. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  8156. + : ScriptInjectionCallback(
  8157. + base::BindOnce(&TimedScriptInjectionCallback::OnCompleted,
  8158. + base::Unretained(this))),
  8159. + injection_(injection) {}
  8160. + ~TimedScriptInjectionCallback() override {}
  8161. +
  8162. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  8163. + if (injection_) {
  8164. + base::TimeTicks timestamp(base::TimeTicks::Now());
  8165. + absl::optional<base::TimeDelta> elapsed;
  8166. + // If the script will never execute (such as if the context is destroyed),
  8167. + // willExecute() will not be called, but OnCompleted() will. Only log a
  8168. + // time for execution if the script, in fact, executed.
  8169. + if (!start_time_.is_null())
  8170. + elapsed = timestamp - start_time_;
  8171. + injection_->OnJsInjectionCompleted(result, elapsed);
  8172. + }
  8173. + }
  8174. +
  8175. + void WillExecute() override {
  8176. + start_time_ = base::TimeTicks::Now();
  8177. + }
  8178. +
  8179. + private:
  8180. + base::WeakPtr<ScriptInjection> injection_;
  8181. + base::TimeTicks start_time_;
  8182. +};
  8183. +
  8184. +} // namespace
  8185. +
  8186. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  8187. +// false.
  8188. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  8189. + public:
  8190. + FrameWatcher(const FrameWatcher&) = delete;
  8191. + FrameWatcher& operator=(const FrameWatcher&) = delete;
  8192. + FrameWatcher(content::RenderFrame* render_frame,
  8193. + ScriptInjection* injection)
  8194. + : content::RenderFrameObserver(render_frame),
  8195. + injection_(injection) {}
  8196. + ~FrameWatcher() override {}
  8197. +
  8198. + private:
  8199. + void WillDetach() override { injection_->invalidate_render_frame(); }
  8200. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  8201. +
  8202. + ScriptInjection* injection_;
  8203. +};
  8204. +
  8205. +// static
  8206. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  8207. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8208. +
  8209. + for (const auto& iter : isolated_worlds) {
  8210. + if (iter.second == isolated_world_id)
  8211. + return iter.first;
  8212. + }
  8213. + return std::string();
  8214. +}
  8215. +
  8216. +// static
  8217. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  8218. + g_isolated_worlds.Get().erase(host_id);
  8219. +}
  8220. +
  8221. +ScriptInjection::ScriptInjection(
  8222. + std::unique_ptr<ScriptInjector> injector,
  8223. + content::RenderFrame* render_frame,
  8224. + std::unique_ptr<const InjectionHost> injection_host,
  8225. + UserScript::RunLocation run_location,
  8226. + bool log_activity)
  8227. + : injector_(std::move(injector)),
  8228. + render_frame_(render_frame),
  8229. + injection_host_(std::move(injection_host)),
  8230. + run_location_(run_location),
  8231. + request_id_(kInvalidRequestId),
  8232. + complete_(false),
  8233. + did_inject_js_(false),
  8234. + log_activity_(log_activity),
  8235. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  8236. + CHECK(injection_host_.get());
  8237. +}
  8238. +
  8239. +ScriptInjection::~ScriptInjection() {
  8240. + if (!complete_)
  8241. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  8242. +}
  8243. +
  8244. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  8245. + UserScript::RunLocation current_location,
  8246. + ScriptsRunInfo* scripts_run_info,
  8247. + CompletionCallback async_completion_callback) {
  8248. + if (current_location < run_location_)
  8249. + return INJECTION_WAITING; // Wait for the right location.
  8250. +
  8251. + if (request_id_ != kInvalidRequestId) {
  8252. + // We're waiting for permission right now, try again later.
  8253. + return INJECTION_WAITING;
  8254. + }
  8255. +
  8256. + if (!injection_host_) {
  8257. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8258. + return INJECTION_FINISHED; // We're done.
  8259. + }
  8260. +
  8261. + InjectionResult result = Inject(scripts_run_info);
  8262. + // If the injection is blocked, we need to set the manager so we can
  8263. + // notify it upon completion.
  8264. + if (result == INJECTION_BLOCKED)
  8265. + async_completion_callback_ = std::move(async_completion_callback);
  8266. + return result;
  8267. +}
  8268. +
  8269. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  8270. + ScriptsRunInfo* scripts_run_info) {
  8271. + if (!injection_host_) {
  8272. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8273. + return INJECTION_FINISHED;
  8274. + }
  8275. +
  8276. + return Inject(scripts_run_info);
  8277. +}
  8278. +
  8279. +void ScriptInjection::OnHostRemoved() {
  8280. + injection_host_.reset(nullptr);
  8281. +}
  8282. +
  8283. +void ScriptInjection::NotifyWillNotInject(
  8284. + ScriptInjector::InjectFailureReason reason) {
  8285. + complete_ = true;
  8286. + injector_->OnWillNotInject(reason, render_frame_);
  8287. +}
  8288. +
  8289. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  8290. + ScriptsRunInfo* scripts_run_info) {
  8291. + DCHECK(injection_host_);
  8292. + //DCHECK(scripts_run_info);
  8293. + DCHECK(!complete_);
  8294. + bool should_inject_js = injector_->ShouldInjectJs(
  8295. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  8296. + bool should_inject_css = injector_->ShouldInjectCss(
  8297. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  8298. +
  8299. + // This can happen if the extension specified a script to
  8300. + // be run in multiple rules, and the script has already run.
  8301. + // See crbug.com/631247.
  8302. + if (!should_inject_js && !should_inject_css) {
  8303. + return INJECTION_FINISHED;
  8304. + }
  8305. +
  8306. + if (should_inject_js)
  8307. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  8308. + &(scripts_run_info->num_js));
  8309. + if (should_inject_css)
  8310. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  8311. + &(scripts_run_info->num_css));
  8312. +
  8313. + complete_ = did_inject_js_ || !should_inject_js;
  8314. +
  8315. + if (complete_) {
  8316. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8317. + render_frame_);
  8318. + } else {
  8319. + ++scripts_run_info->num_blocking_js;
  8320. + }
  8321. +
  8322. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  8323. +}
  8324. +
  8325. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  8326. + size_t* num_injected_js_scripts) {
  8327. + DCHECK(!did_inject_js_);
  8328. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  8329. + run_location_, executing_scripts, num_injected_js_scripts);
  8330. + DCHECK(!sources.empty());
  8331. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  8332. + bool is_user_gesture = injector_->IsUserGesture();
  8333. +
  8334. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  8335. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  8336. +
  8337. + base::ElapsedTimer exec_timer;
  8338. +
  8339. + // For content scripts executing during page load, we run them asynchronously
  8340. + // in order to reduce UI jank experienced by the user. (We don't do this for
  8341. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  8342. + // run, so we run them as soon as we can.)
  8343. + // Note: We could potentially also run deferred and browser-driven scripts
  8344. + // asynchronously; however, these are rare enough that there probably isn't
  8345. + // UI jank. If this changes, we can update this.
  8346. + bool should_execute_asynchronously =
  8347. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  8348. + (run_location_ == UserScript::DOCUMENT_END ||
  8349. + run_location_ == UserScript::DOCUMENT_IDLE);
  8350. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  8351. + should_execute_asynchronously
  8352. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  8353. + : blink::WebLocalFrame::kSynchronous;
  8354. +
  8355. + render_frame_->GetWebFrame()->RequestExecuteScript(
  8356. + world_id, sources, is_user_gesture,
  8357. + execution_option, callback.release(),
  8358. + blink::BackForwardCacheAware::kPossiblyDisallow,
  8359. + blink::WebLocalFrame::PromiseBehavior::kDontWait);
  8360. +}
  8361. +
  8362. +void ScriptInjection::OnJsInjectionCompleted(
  8363. + const std::vector<v8::Local<v8::Value>>& results,
  8364. + absl::optional<base::TimeDelta> elapsed) {
  8365. + DCHECK(!did_inject_js_);
  8366. +
  8367. + bool expects_results = injector_->ExpectsResults();
  8368. + if (expects_results) {
  8369. + if (!results.empty() && !results[0].IsEmpty()) {
  8370. + // Right now, we only support returning single results (per frame).
  8371. + // It's safe to always use the main world context when converting
  8372. + // here. V8ValueConverterImpl shouldn't actually care about the
  8373. + // context scope, and it switches to v8::Object's creation context
  8374. + // when encountered.
  8375. + v8::Local<v8::Context> context =
  8376. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  8377. + execution_result_ =
  8378. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  8379. + }
  8380. + if (!execution_result_.get())
  8381. + execution_result_ = std::make_unique<base::Value>();
  8382. + }
  8383. + did_inject_js_ = true;
  8384. +
  8385. + // If |async_completion_callback_| is set, it means the script finished
  8386. + // asynchronously, and we should run it.
  8387. + if (!async_completion_callback_.is_null()) {
  8388. + complete_ = true;
  8389. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8390. + render_frame_);
  8391. + // Warning: this object can be destroyed after this line!
  8392. + std::move(async_completion_callback_).Run(this);
  8393. + }
  8394. +}
  8395. +
  8396. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  8397. + size_t* num_injected_stylesheets) {
  8398. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  8399. + run_location_, injected_stylesheets, num_injected_stylesheets);
  8400. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  8401. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  8402. + absl::optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  8403. + blink::WebDocument::CSSOrigin blink_css_origin =
  8404. + css_origin && *css_origin == CSS_ORIGIN_USER
  8405. + ? blink::WebDocument::kUserOrigin
  8406. + : blink::WebDocument::kAuthorOrigin;
  8407. + blink::WebStyleSheetKey style_sheet_key;
  8408. + if (const absl::optional<std::string>& injection_key =
  8409. + injector_->GetInjectionKey())
  8410. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  8411. + for (const blink::WebString& css : css_sources)
  8412. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  8413. + blink_css_origin);
  8414. +}
  8415. +
  8416. +} // namespace extensions
  8417. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  8418. new file mode 100755
  8419. --- /dev/null
  8420. +++ b/components/user_scripts/renderer/script_injection.h
  8421. @@ -0,0 +1,154 @@
  8422. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8423. +// Use of this source code is governed by a BSD-style license that can be
  8424. +// found in the LICENSE file.
  8425. +
  8426. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8427. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8428. +
  8429. +#include <stdint.h>
  8430. +
  8431. +#include <memory>
  8432. +#include <vector>
  8433. +
  8434. +#include "base/callback.h"
  8435. +#include "base/memory/weak_ptr.h"
  8436. +#include "../common/user_script.h"
  8437. +#include "injection_host.h"
  8438. +#include "script_injector.h"
  8439. +
  8440. +struct HostID;
  8441. +
  8442. +namespace content {
  8443. +class RenderFrame;
  8444. +}
  8445. +
  8446. +namespace v8 {
  8447. +class Value;
  8448. +template <class T> class Local;
  8449. +}
  8450. +
  8451. +namespace user_scripts {
  8452. +struct ScriptsRunInfo;
  8453. +
  8454. +// A script wrapper which is aware of whether or not it is allowed to execute,
  8455. +// and contains the implementation to do so.
  8456. +class ScriptInjection {
  8457. + public:
  8458. + ScriptInjection(const ScriptInjection&) = delete;
  8459. + ScriptInjection& operator=(const ScriptInjection&) = delete;
  8460. + enum InjectionResult {
  8461. + INJECTION_FINISHED,
  8462. + INJECTION_BLOCKED,
  8463. + INJECTION_WAITING
  8464. + };
  8465. +
  8466. + using CompletionCallback = base::OnceCallback<void(ScriptInjection*)>;
  8467. +
  8468. + // Return the id of the injection host associated with the given world.
  8469. + static std::string GetHostIdForIsolatedWorld(int world_id);
  8470. +
  8471. + // Remove the isolated world associated with the given injection host.
  8472. + static void RemoveIsolatedWorld(const std::string& host_id);
  8473. +
  8474. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  8475. + content::RenderFrame* render_frame,
  8476. + std::unique_ptr<const InjectionHost> injection_host,
  8477. + UserScript::RunLocation run_location,
  8478. + bool log_activity);
  8479. + ~ScriptInjection();
  8480. +
  8481. + // Try to inject the script at the |current_location|. This returns
  8482. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  8483. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  8484. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  8485. + // for permission purposes or because |current_location| is not the designated
  8486. + // |run_location_|).
  8487. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  8488. + // called upon completion.
  8489. + InjectionResult TryToInject(
  8490. + UserScript::RunLocation current_location,
  8491. + ScriptsRunInfo* scripts_run_info,
  8492. + CompletionCallback async_completion_callback);
  8493. +
  8494. + // Called when permission for the given injection has been granted.
  8495. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  8496. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  8497. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  8498. +
  8499. + // Resets the pointer of the injection host when the host is gone.
  8500. + void OnHostRemoved();
  8501. +
  8502. + void invalidate_render_frame() { render_frame_ = nullptr; }
  8503. +
  8504. + // Accessors.
  8505. + content::RenderFrame* render_frame() const { return render_frame_; }
  8506. + const HostID& host_id() const { return injection_host_->id(); }
  8507. + int64_t request_id() const { return request_id_; }
  8508. +
  8509. + // Called when JS injection for the given frame has been completed or
  8510. + // cancelled.
  8511. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  8512. + absl::optional<base::TimeDelta> elapsed);
  8513. +
  8514. + private:
  8515. + class FrameWatcher;
  8516. +
  8517. + // Sends a message to the browser to request permission to inject.
  8518. + void RequestPermissionFromBrowser();
  8519. +
  8520. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  8521. + // otherwise INJECTION_BLOCKED.
  8522. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  8523. +
  8524. + // Inject any JS scripts into the frame for the injection.
  8525. + void InjectJs(std::set<std::string>* executing_scripts,
  8526. + size_t* num_injected_js_scripts);
  8527. +
  8528. + // Inject any CSS source into the frame for the injection.
  8529. + void InjectCss(std::set<std::string>* injected_stylesheets,
  8530. + size_t* num_injected_stylesheets);
  8531. +
  8532. + // Notify that we will not inject, and mark it as acknowledged.
  8533. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  8534. +
  8535. + // The injector for this injection.
  8536. + std::unique_ptr<ScriptInjector> injector_;
  8537. +
  8538. + // The RenderFrame into which this should inject the script.
  8539. + content::RenderFrame* render_frame_;
  8540. +
  8541. + // The associated injection host.
  8542. + std::unique_ptr<const InjectionHost> injection_host_;
  8543. +
  8544. + // The location in the document load at which we inject the script.
  8545. + UserScript::RunLocation run_location_;
  8546. +
  8547. + // This injection's request id. This will be -1 unless the injection is
  8548. + // currently waiting on permission.
  8549. + int64_t request_id_;
  8550. +
  8551. + // Whether or not the injection is complete, either via injecting the script
  8552. + // or because it will never complete.
  8553. + bool complete_;
  8554. +
  8555. + // Whether or not the injection successfully injected JS.
  8556. + bool did_inject_js_;
  8557. +
  8558. + // Whether or not we should log dom activity for this injection.
  8559. + bool log_activity_;
  8560. +
  8561. + // Results storage.
  8562. + std::unique_ptr<base::Value> execution_result_;
  8563. +
  8564. + // The callback to run upon completing asynchronously.
  8565. + CompletionCallback async_completion_callback_;
  8566. +
  8567. + // A helper class to hold the render frame and watch for its deletion.
  8568. + std::unique_ptr<FrameWatcher> frame_watcher_;
  8569. +
  8570. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  8571. +};
  8572. +
  8573. +} // namespace extensions
  8574. +
  8575. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8576. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  8577. new file mode 100755
  8578. --- /dev/null
  8579. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  8580. @@ -0,0 +1,25 @@
  8581. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8582. +// Use of this source code is governed by a BSD-style license that can be
  8583. +// found in the LICENSE file.
  8584. +
  8585. +#include "script_injection_callback.h"
  8586. +
  8587. +#include "third_party/blink/public/platform/web_vector.h"
  8588. +
  8589. +namespace user_scripts {
  8590. +
  8591. +ScriptInjectionCallback::ScriptInjectionCallback(
  8592. + CompleteCallback injection_completed_callback)
  8593. + : injection_completed_callback_(std::move(injection_completed_callback)) {}
  8594. +
  8595. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  8596. +}
  8597. +
  8598. +void ScriptInjectionCallback::Completed(
  8599. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  8600. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  8601. + std::move(injection_completed_callback_).Run(stl_result);
  8602. + delete this;
  8603. +}
  8604. +
  8605. +} // namespace extensions
  8606. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  8607. new file mode 100755
  8608. --- /dev/null
  8609. +++ b/components/user_scripts/renderer/script_injection_callback.h
  8610. @@ -0,0 +1,38 @@
  8611. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8612. +// Use of this source code is governed by a BSD-style license that can be
  8613. +// found in the LICENSE file.
  8614. +
  8615. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8616. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8617. +
  8618. +#include <vector>
  8619. +
  8620. +#include "base/callback.h"
  8621. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  8622. +#include "v8/include/v8.h"
  8623. +
  8624. +namespace user_scripts {
  8625. +
  8626. +// A wrapper around a callback to notify a script injection when injection
  8627. +// completes.
  8628. +// This class manages its own lifetime.
  8629. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  8630. + public:
  8631. + ScriptInjectionCallback(const ScriptInjectionCallback&) = delete;
  8632. + ScriptInjectionCallback& operator=(const ScriptInjectionCallback&) = delete;
  8633. + using CompleteCallback =
  8634. + base::OnceCallback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  8635. +
  8636. + explicit ScriptInjectionCallback(
  8637. + CompleteCallback injection_completed_callback);
  8638. + ~ScriptInjectionCallback() override;
  8639. +
  8640. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  8641. +
  8642. + private:
  8643. + CompleteCallback injection_completed_callback_;
  8644. +};
  8645. +
  8646. +} // namespace extensions
  8647. +
  8648. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8649. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  8650. new file mode 100755
  8651. --- /dev/null
  8652. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  8653. @@ -0,0 +1,417 @@
  8654. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8655. +// Use of this source code is governed by a BSD-style license that can be
  8656. +// found in the LICENSE file.
  8657. +
  8658. +#include "script_injection_manager.h"
  8659. +
  8660. +#include <memory>
  8661. +#include <utility>
  8662. +
  8663. +#include "base/auto_reset.h"
  8664. +#include "base/bind.h"
  8665. +#include "base/feature_list.h"
  8666. +#include "base/memory/weak_ptr.h"
  8667. +#include "base/threading/thread_task_runner_handle.h"
  8668. +#include "base/values.h"
  8669. +#include "base/logging.h"
  8670. +#include "content/public/renderer/render_frame.h"
  8671. +#include "content/public/renderer/render_frame_observer.h"
  8672. +#include "content/public/renderer/render_thread.h"
  8673. +#include "extension_frame_helper.h"
  8674. +#include "../common/host_id.h"
  8675. +#include "script_injection.h"
  8676. +#include "scripts_run_info.h"
  8677. +#include "web_ui_injection_host.h"
  8678. +#include "ipc/ipc_message_macros.h"
  8679. +#include "third_party/blink/public/platform/web_url_error.h"
  8680. +#include "third_party/blink/public/web/web_document.h"
  8681. +#include "third_party/blink/public/web/web_frame.h"
  8682. +#include "third_party/blink/public/web/web_local_frame.h"
  8683. +#include "third_party/blink/public/web/web_view.h"
  8684. +#include "url/gurl.h"
  8685. +#include "../common/user_scripts_features.h"
  8686. +
  8687. +namespace user_scripts {
  8688. +
  8689. +namespace {
  8690. +
  8691. +// The length of time to wait after the DOM is complete to try and run user
  8692. +// scripts.
  8693. +const int kScriptIdleTimeoutInMs = 200;
  8694. +
  8695. +// Returns the RunLocation that follows |run_location|.
  8696. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  8697. + switch (run_location) {
  8698. + case UserScript::DOCUMENT_START:
  8699. + return UserScript::DOCUMENT_END;
  8700. + case UserScript::DOCUMENT_END:
  8701. + return UserScript::DOCUMENT_IDLE;
  8702. + case UserScript::DOCUMENT_IDLE:
  8703. + return UserScript::RUN_LOCATION_LAST;
  8704. + case UserScript::UNDEFINED:
  8705. + case UserScript::RUN_DEFERRED:
  8706. + case UserScript::BROWSER_DRIVEN:
  8707. + case UserScript::RUN_LOCATION_LAST:
  8708. + break;
  8709. + }
  8710. + NOTREACHED();
  8711. + return UserScript::RUN_LOCATION_LAST;
  8712. +}
  8713. +
  8714. +} // namespace
  8715. +
  8716. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  8717. + public:
  8718. + RFOHelper(content::RenderFrame* render_frame,
  8719. + ScriptInjectionManager* manager);
  8720. + ~RFOHelper() override;
  8721. +
  8722. + // commit @9f2aac4
  8723. + void Initialize();
  8724. +
  8725. + private:
  8726. + // RenderFrameObserver implementation.
  8727. + void DidCreateNewDocument() override;
  8728. + void DidCreateDocumentElement() override;
  8729. + void DidFailProvisionalLoad() override;
  8730. + void DidDispatchDOMContentLoadedEvent() override;
  8731. + void WillDetach() override;
  8732. + void OnDestruct() override;
  8733. + void OnStop() override;
  8734. +
  8735. + // Tells the ScriptInjectionManager to run tasks associated with
  8736. + // document_idle.
  8737. + void RunIdle();
  8738. +
  8739. + void StartInjectScripts(UserScript::RunLocation run_location);
  8740. +
  8741. + // Indicate that the frame is no longer valid because it is starting
  8742. + // a new load or closing.
  8743. + void InvalidateAndResetFrame(bool force_reset);
  8744. +
  8745. + // The owning ScriptInjectionManager.
  8746. + ScriptInjectionManager* manager_;
  8747. +
  8748. + bool should_run_idle_ = true; // commit @9f2aac4
  8749. +
  8750. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  8751. +};
  8752. +
  8753. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  8754. + ScriptInjectionManager* manager)
  8755. + : content::RenderFrameObserver(render_frame),
  8756. + manager_(manager),
  8757. + should_run_idle_(true) {}
  8758. +
  8759. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  8760. +}
  8761. +
  8762. +
  8763. +void ScriptInjectionManager::RFOHelper::Initialize() {
  8764. + // Set up for the initial empty document, for which the Document created
  8765. + // events do not happen as it's already present.
  8766. + DidCreateNewDocument();
  8767. + // The initial empty document for a main frame may have scripts attached to it
  8768. + // but we do not want to invalidate the frame and lose them when the next
  8769. + // document loads. For example the IncognitoApiTest.IncognitoSplitMode test
  8770. + // does `chrome.tabs.create()` with a script to be run, which is added to the
  8771. + // frame before it navigates, so it needs to be preserved. However scripts in
  8772. + // child frames are expected to be run inside the initial empty document. For
  8773. + // example the ExecuteScriptApiTest.FrameWithHttp204 test creates a child
  8774. + // frame at about:blank and expects to run injected scripts inside it.
  8775. + // This is all quite inconsistent however tests both depend on us queuing and
  8776. + // not queueing the DOCUMENT_START events in the initial empty document.
  8777. + if (!render_frame()->IsMainFrame()) {
  8778. + DidCreateDocumentElement();
  8779. + }
  8780. +}
  8781. +
  8782. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  8783. + // A new document is going to be shown, so invalidate the old document state.
  8784. + // Don't force-reset the frame, because it is possible that a script injection
  8785. + // was scheduled before the page was loaded, e.g. by navigating to a
  8786. + // javascript: URL before the page has loaded.
  8787. + constexpr bool kForceReset = false;
  8788. + InvalidateAndResetFrame(kForceReset);
  8789. +}
  8790. +
  8791. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  8792. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8793. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  8794. +
  8795. + ExtensionFrameHelper::Get(render_frame())
  8796. + ->ScheduleAtDocumentStart(
  8797. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8798. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  8799. +}
  8800. +
  8801. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  8802. + auto it = manager_->frame_statuses_.find(render_frame());
  8803. + if (it != manager_->frame_statuses_.end() &&
  8804. + it->second == UserScript::DOCUMENT_START) {
  8805. + // Since the provisional load failed, the frame stays at its previous loaded
  8806. + // state and origin (or the parent's origin for new/about:blank frames).
  8807. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  8808. + // done loading, and avoid any deadlock in the system.
  8809. + //
  8810. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  8811. + // injections closely follow the DOMContentLoaded (and onload) events, which
  8812. + // are not triggered after a failed provisional load.
  8813. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  8814. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  8815. + constexpr bool kForceReset = true;
  8816. + InvalidateAndResetFrame(kForceReset);
  8817. + should_run_idle_ = false;
  8818. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  8819. + }
  8820. +}
  8821. +
  8822. +void ScriptInjectionManager::RFOHelper::DidDispatchDOMContentLoadedEvent() {
  8823. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8824. + LOG(INFO) << "UserScripts: DidDispatchDOMContentLoadedEvent -> DOCUMENT_END";
  8825. +
  8826. + DCHECK(content::RenderThread::Get());
  8827. + ExtensionFrameHelper::Get(render_frame())
  8828. + ->ScheduleAtDocumentEnd(
  8829. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8830. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8831. +
  8832. + // We try to run idle in two places: a delayed task here and in response to
  8833. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidDispatchDOMContentLoadedEvent()
  8834. + // corresponds to completing the document's load, whereas
  8835. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8836. + // subresources' load (but before the window.onload event). We don't want to
  8837. + // hold up script injection for a particularly slow subresource, so we set a
  8838. + // delayed task from here - but if we finish everything before that point
  8839. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8840. + // keep waiting.
  8841. + render_frame()
  8842. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8843. + ->PostDelayedTask(
  8844. + FROM_HERE,
  8845. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8846. + weak_factory_.GetWeakPtr()),
  8847. + base::Milliseconds(kScriptIdleTimeoutInMs));
  8848. +
  8849. + ExtensionFrameHelper::Get(render_frame())
  8850. + ->ScheduleAtDocumentIdle(
  8851. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8852. + weak_factory_.GetWeakPtr()));
  8853. +}
  8854. +
  8855. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8856. + // The frame is closing - invalidate.
  8857. + constexpr bool kForceReset = true;
  8858. + InvalidateAndResetFrame(kForceReset);
  8859. +}
  8860. +
  8861. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8862. + manager_->RemoveObserver(this);
  8863. +}
  8864. +
  8865. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8866. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8867. + // extension to avoid keeping the frame in a START state indefinitely which
  8868. + // leads to deadlocks.
  8869. + DidFailProvisionalLoad();
  8870. +}
  8871. +
  8872. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8873. + // Only notify the manager if the frame hasn't already had idle run since the
  8874. + // task to RunIdle() was posted.
  8875. + if (should_run_idle_) {
  8876. + should_run_idle_ = false;
  8877. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8878. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8879. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8880. + }
  8881. +}
  8882. +
  8883. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8884. + UserScript::RunLocation run_location) {
  8885. + manager_->StartInjectScripts(render_frame(), run_location);
  8886. +}
  8887. +
  8888. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8889. + bool force_reset) {
  8890. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8891. + weak_factory_.InvalidateWeakPtrs();
  8892. + // We reset to inject on idle, because the frame can be reused (in the case of
  8893. + // navigation).
  8894. + should_run_idle_ = true;
  8895. +
  8896. + // Reset the frame if either |force_reset| is true, or if the manager is
  8897. + // keeping track of the state of the frame (in which case we need to clean it
  8898. + // up).
  8899. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8900. + manager_->InvalidateForFrame(render_frame());
  8901. +}
  8902. +
  8903. +ScriptInjectionManager::ScriptInjectionManager(
  8904. + UserScriptSetManager* user_script_set_manager)
  8905. + : user_script_set_manager_(user_script_set_manager),
  8906. + user_script_set_manager_observation_(this) {
  8907. + user_script_set_manager_observation_.Observe(user_script_set_manager_);
  8908. +}
  8909. +
  8910. +ScriptInjectionManager::~ScriptInjectionManager() {
  8911. + for (const auto& injection : pending_injections_)
  8912. + injection->invalidate_render_frame();
  8913. + for (const auto& injection : running_injections_)
  8914. + injection->invalidate_render_frame();
  8915. +}
  8916. +
  8917. +void ScriptInjectionManager::OnRenderFrameCreated(
  8918. + content::RenderFrame* render_frame) {
  8919. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8920. + rfo_helpers_.back()->Initialize(); // commit @9f2aac4
  8921. +}
  8922. +
  8923. +void ScriptInjectionManager::OnInjectionFinished(
  8924. + ScriptInjection* injection) {
  8925. + auto iter =
  8926. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8927. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8928. + return injection == mode.get();
  8929. + });
  8930. + if (iter != running_injections_.end())
  8931. + running_injections_.erase(iter);
  8932. +}
  8933. +
  8934. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8935. + const std::set<HostID>& changed_hosts) {
  8936. + for (auto iter = pending_injections_.begin();
  8937. + iter != pending_injections_.end();) {
  8938. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8939. + iter = pending_injections_.erase(iter);
  8940. + else
  8941. + ++iter;
  8942. + }
  8943. +}
  8944. +
  8945. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8946. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8947. + if (iter->get() == helper) {
  8948. + rfo_helpers_.erase(iter);
  8949. + break;
  8950. + }
  8951. + }
  8952. +}
  8953. +
  8954. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8955. + // If the frame invalidated is the frame being injected into, we need to
  8956. + // note it.
  8957. + active_injection_frames_.erase(frame);
  8958. +
  8959. + for (auto iter = pending_injections_.begin();
  8960. + iter != pending_injections_.end();) {
  8961. + if ((*iter)->render_frame() == frame)
  8962. + iter = pending_injections_.erase(iter);
  8963. + else
  8964. + ++iter;
  8965. + }
  8966. +
  8967. + frame_statuses_.erase(frame);
  8968. +}
  8969. +
  8970. +void ScriptInjectionManager::StartInjectScripts(
  8971. + content::RenderFrame* frame,
  8972. + UserScript::RunLocation run_location) {
  8973. + auto iter = frame_statuses_.find(frame);
  8974. + // We also don't execute if we detect that the run location is somehow out of
  8975. + // order. This can happen if:
  8976. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8977. + // - The run location reported doesn't immediately follow the previous
  8978. + // reported run location.
  8979. + // We don't want to run because extensions may have requirements that scripts
  8980. + // running in an earlier run location have run by the time a later script
  8981. + // runs. Better to just not run.
  8982. + // Note that we check run_location > NextRunLocation() in the second clause
  8983. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8984. + // can happen multiple times, so we can receive earlier/equal run locations.
  8985. + if ((iter == frame_statuses_.end() &&
  8986. + run_location != UserScript::DOCUMENT_START) ||
  8987. + (iter != frame_statuses_.end() &&
  8988. + run_location > NextRunLocation(iter->second))) {
  8989. + // We also invalidate the frame, because the run order of pending injections
  8990. + // may also be bad.
  8991. + InvalidateForFrame(frame);
  8992. + return;
  8993. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8994. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8995. + // multiple times. Ignore the subsequent signals.
  8996. + return;
  8997. + }
  8998. +
  8999. + // Otherwise, all is right in the world, and we can get on with the
  9000. + // injections!
  9001. + frame_statuses_[frame] = run_location;
  9002. + InjectScripts(frame, run_location);
  9003. +}
  9004. +
  9005. +void ScriptInjectionManager::InjectScripts(
  9006. + content::RenderFrame* frame,
  9007. + UserScript::RunLocation run_location) {
  9008. + // Find any injections that want to run on the given frame.
  9009. + ScriptInjectionVector frame_injections;
  9010. + for (auto iter = pending_injections_.begin();
  9011. + iter != pending_injections_.end();) {
  9012. + if ((*iter)->render_frame() == frame) {
  9013. + frame_injections.push_back(std::move(*iter));
  9014. + iter = pending_injections_.erase(iter);
  9015. + } else {
  9016. + ++iter;
  9017. + }
  9018. + }
  9019. +
  9020. + // Add any injections for user scripts.
  9021. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  9022. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  9023. + run_location);
  9024. +
  9025. + // Note that we are running in |frame|.
  9026. + active_injection_frames_.insert(frame);
  9027. +
  9028. + ScriptsRunInfo scripts_run_info(frame, run_location);
  9029. +
  9030. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  9031. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  9032. + // (if a script removes its own frame, for example). If this happens, abort.
  9033. + if (!active_injection_frames_.count(frame))
  9034. + break;
  9035. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  9036. + iter = frame_injections.erase(iter);
  9037. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  9038. + }
  9039. +
  9040. + // We are done running in the frame.
  9041. + active_injection_frames_.erase(frame);
  9042. +
  9043. + scripts_run_info.LogRun(activity_logging_enabled_);
  9044. +}
  9045. +
  9046. +void ScriptInjectionManager::TryToInject(
  9047. + std::unique_ptr<ScriptInjection> injection,
  9048. + UserScript::RunLocation run_location,
  9049. + ScriptsRunInfo* scripts_run_info) {
  9050. + // Try to inject the script. If the injection is waiting (i.e., for
  9051. + // permission), add it to the list of pending injections. If the injection
  9052. + // has blocked, add it to the list of running injections.
  9053. + // The Unretained below is safe because this object owns all the
  9054. + // ScriptInjections, so is guaranteed to outlive them.
  9055. + switch (injection->TryToInject(
  9056. + run_location, scripts_run_info,
  9057. + base::BindOnce(&ScriptInjectionManager::OnInjectionFinished,
  9058. + base::Unretained(this)))) {
  9059. + case ScriptInjection::INJECTION_WAITING:
  9060. + pending_injections_.push_back(std::move(injection));
  9061. + break;
  9062. + case ScriptInjection::INJECTION_BLOCKED:
  9063. + running_injections_.push_back(std::move(injection));
  9064. + break;
  9065. + case ScriptInjection::INJECTION_FINISHED:
  9066. + break;
  9067. + }
  9068. +}
  9069. +
  9070. +} // namespace extensions
  9071. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  9072. new file mode 100755
  9073. --- /dev/null
  9074. +++ b/components/user_scripts/renderer/script_injection_manager.h
  9075. @@ -0,0 +1,101 @@
  9076. +#include <stdint.h>
  9077. +
  9078. +#include <map>
  9079. +#include <set>
  9080. +#include <string>
  9081. +#include <vector>
  9082. +
  9083. +#include "base/callback.h"
  9084. +#include "base/scoped_observation.h"
  9085. +#include "../common/user_script.h"
  9086. +#include "script_injection.h"
  9087. +#include "user_script_set_manager.h"
  9088. +
  9089. +namespace user_scripts {
  9090. +
  9091. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  9092. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  9093. +// maintaining any pending injections awaiting permission or the appropriate
  9094. +// load point, and injecting them when ready.
  9095. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  9096. + public:
  9097. + ScriptInjectionManager(const ScriptInjectionManager&) = delete;
  9098. + ScriptInjectionManager& operator=(const ScriptInjectionManager&) = delete;
  9099. + explicit ScriptInjectionManager(
  9100. + UserScriptSetManager* user_script_set_manager);
  9101. + virtual ~ScriptInjectionManager();
  9102. +
  9103. + // Notifies that a new render view has been created.
  9104. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  9105. +
  9106. + // Removes pending injections of the unloaded extension.
  9107. + //void OnExtensionUnloaded(const std::string& extension_id);
  9108. +
  9109. + void set_activity_logging_enabled(bool enabled) {
  9110. + activity_logging_enabled_ = enabled;
  9111. + }
  9112. +
  9113. + private:
  9114. + // A RenderFrameObserver implementation which watches the various render
  9115. + // frames in order to notify the ScriptInjectionManager of different
  9116. + // document load states and IPCs.
  9117. + class RFOHelper;
  9118. +
  9119. + using FrameStatusMap =
  9120. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  9121. +
  9122. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  9123. +
  9124. + // Notifies that an injection has been finished.
  9125. + void OnInjectionFinished(ScriptInjection* injection);
  9126. +
  9127. + // UserScriptSetManager::Observer implementation.
  9128. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  9129. +
  9130. + // Notifies that an RFOHelper should be removed.
  9131. + void RemoveObserver(RFOHelper* helper);
  9132. +
  9133. + // Invalidate any pending tasks associated with |frame|.
  9134. + void InvalidateForFrame(content::RenderFrame* frame);
  9135. +
  9136. + // Starts the process to inject appropriate scripts into |frame|.
  9137. + void StartInjectScripts(content::RenderFrame* frame,
  9138. + UserScript::RunLocation run_location);
  9139. +
  9140. + // Actually injects the scripts into |frame|.
  9141. + void InjectScripts(content::RenderFrame* frame,
  9142. + UserScript::RunLocation run_location);
  9143. +
  9144. + // Try to inject and store injection if it has not finished.
  9145. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  9146. + UserScript::RunLocation run_location,
  9147. + ScriptsRunInfo* scripts_run_info);
  9148. +
  9149. + // The map of active web frames to their corresponding statuses. The
  9150. + // RunLocation of the frame corresponds to the last location that has ran.
  9151. + FrameStatusMap frame_statuses_;
  9152. +
  9153. + // The frames currently being injected into, so long as that frame is valid.
  9154. + std::set<content::RenderFrame*> active_injection_frames_;
  9155. +
  9156. + // The collection of RFOHelpers.
  9157. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  9158. +
  9159. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  9160. + UserScriptSetManager* user_script_set_manager_;
  9161. +
  9162. + // Pending injections which are waiting for either the proper run location or
  9163. + // user consent.
  9164. + ScriptInjectionVector pending_injections_;
  9165. +
  9166. + // Running injections which are waiting for async callbacks from blink.
  9167. + ScriptInjectionVector running_injections_;
  9168. +
  9169. + // Whether or not dom activity should be logged for scripts injected.
  9170. + bool activity_logging_enabled_ = false;
  9171. +
  9172. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  9173. + user_script_set_manager_observation_{this};
  9174. +};
  9175. +
  9176. +}
  9177. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  9178. new file mode 100755
  9179. --- /dev/null
  9180. +++ b/components/user_scripts/renderer/script_injector.h
  9181. @@ -0,0 +1,96 @@
  9182. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9183. +// Use of this source code is governed by a BSD-style license that can be
  9184. +// found in the LICENSE file.
  9185. +
  9186. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9187. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9188. +
  9189. +#include <memory>
  9190. +#include <vector>
  9191. +
  9192. +#include "../common/constants.h"
  9193. +#include "../common/user_script.h"
  9194. +#include "third_party/blink/public/web/web_script_source.h"
  9195. +
  9196. +class InjectionHost;
  9197. +
  9198. +namespace blink {
  9199. +class WebLocalFrame;
  9200. +}
  9201. +
  9202. +namespace user_scripts {
  9203. +
  9204. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  9205. +// information about how to inject the script, including what code to inject and
  9206. +// when (run location), but without any injection logic.
  9207. +class ScriptInjector {
  9208. + public:
  9209. + // The possible reasons for not injecting the script.
  9210. + enum InjectFailureReason {
  9211. + EXTENSION_REMOVED, // The extension was removed before injection.
  9212. + NOT_ALLOWED, // The script is not allowed to inject.
  9213. + WONT_INJECT // The injection won't inject because the user rejected
  9214. + // (or just did not accept) the injection.
  9215. + };
  9216. +
  9217. + virtual ~ScriptInjector() {}
  9218. +
  9219. + // Returns the script type of this particular injection.
  9220. + virtual UserScript::InjectionType script_type() const = 0;
  9221. +
  9222. + // Returns true if the script is running inside a user gesture.
  9223. + virtual bool IsUserGesture() const = 0;
  9224. +
  9225. + // Returns the CSS origin of this injection.
  9226. + virtual absl::optional<CSSOrigin> GetCssOrigin() const = 0;
  9227. +
  9228. + // Returns the key for this injection, if it's a CSS injection.
  9229. + virtual const absl::optional<std::string> GetInjectionKey() const = 0;
  9230. +
  9231. + // Returns true if the script expects results.
  9232. + virtual bool ExpectsResults() const = 0;
  9233. +
  9234. + // Returns true if the script should inject JS source at the given
  9235. + // |run_location|.
  9236. + virtual bool ShouldInjectJs(
  9237. + UserScript::RunLocation run_location,
  9238. + const std::set<std::string>& executing_scripts) const = 0;
  9239. +
  9240. + // Returns true if the script should inject CSS at the given |run_location|.
  9241. + virtual bool ShouldInjectCss(
  9242. + UserScript::RunLocation run_location,
  9243. + const std::set<std::string>& injected_stylesheets) const = 0;
  9244. +
  9245. + // Returns the javascript sources to inject at the given |run_location|.
  9246. + // Only called if ShouldInjectJs() is true.
  9247. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  9248. + UserScript::RunLocation run_location,
  9249. + std::set<std::string>* executing_scripts,
  9250. + size_t* num_injected_js_scripts) const = 0;
  9251. +
  9252. + // Returns the css to inject at the given |run_location|.
  9253. + // Only called if ShouldInjectCss() is true.
  9254. + virtual std::vector<blink::WebString> GetCssSources(
  9255. + UserScript::RunLocation run_location,
  9256. + std::set<std::string>* injected_stylesheets,
  9257. + size_t* num_injected_stylesheets) const = 0;
  9258. +
  9259. + // Notifies the script that injection has completed, with a possibly-populated
  9260. + // list of results (depending on whether or not ExpectsResults() was true).
  9261. + // |render_frame| contains the render frame, or null if the frame was
  9262. + // invalidated.
  9263. + virtual void OnInjectionComplete(
  9264. + std::unique_ptr<base::Value> execution_result,
  9265. + UserScript::RunLocation run_location,
  9266. + content::RenderFrame* render_frame) = 0;
  9267. +
  9268. + // Notifies the script that injection will never occur.
  9269. + // |render_frame| contains the render frame, or null if the frame was
  9270. + // invalidated.
  9271. + virtual void OnWillNotInject(InjectFailureReason reason,
  9272. + content::RenderFrame* render_frame) = 0;
  9273. +};
  9274. +
  9275. +} // namespace extensions
  9276. +
  9277. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9278. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  9279. new file mode 100755
  9280. --- /dev/null
  9281. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  9282. @@ -0,0 +1,31 @@
  9283. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9284. +// Use of this source code is governed by a BSD-style license that can be
  9285. +// found in the LICENSE file.
  9286. +
  9287. +#include "scripts_run_info.h"
  9288. +
  9289. +#include "base/metrics/histogram_macros.h"
  9290. +#include "content/public/renderer/render_frame.h"
  9291. +#include "content/public/renderer/render_thread.h"
  9292. +#include "script_context.h"
  9293. +#include "third_party/blink/public/web/web_local_frame.h"
  9294. +
  9295. +namespace user_scripts {
  9296. +
  9297. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  9298. + UserScript::RunLocation location)
  9299. + : num_css(0u),
  9300. + num_js(0u),
  9301. + num_blocking_js(0u),
  9302. + routing_id_(render_frame->GetRoutingID()),
  9303. + run_location_(location),
  9304. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  9305. + render_frame->GetWebFrame())) {}
  9306. +
  9307. +ScriptsRunInfo::~ScriptsRunInfo() {
  9308. +}
  9309. +
  9310. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  9311. +}
  9312. +
  9313. +} // namespace extensions
  9314. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  9315. new file mode 100755
  9316. --- /dev/null
  9317. +++ b/components/user_scripts/renderer/scripts_run_info.h
  9318. @@ -0,0 +1,69 @@
  9319. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9320. +// Use of this source code is governed by a BSD-style license that can be
  9321. +// found in the LICENSE file.
  9322. +
  9323. +#ifndef USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9324. +#define USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9325. +
  9326. +#include <stddef.h>
  9327. +
  9328. +#include <map>
  9329. +#include <set>
  9330. +#include <string>
  9331. +
  9332. +#include "base/timer/elapsed_timer.h"
  9333. +#include "../common/user_script.h"
  9334. +
  9335. +namespace content {
  9336. +class RenderFrame;
  9337. +}
  9338. +
  9339. +namespace user_scripts {
  9340. +
  9341. +// A struct containing information about a script run.
  9342. +struct ScriptsRunInfo {
  9343. + ScriptsRunInfo(const ScriptsRunInfo&) = delete;
  9344. + ScriptsRunInfo& operator=(const ScriptsRunInfo&) = delete;
  9345. + // Map of extensions IDs to the executing script paths.
  9346. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  9347. +
  9348. + ScriptsRunInfo(content::RenderFrame* render_frame,
  9349. + UserScript::RunLocation location);
  9350. + ~ScriptsRunInfo();
  9351. +
  9352. + // The number of CSS scripts injected.
  9353. + size_t num_css;
  9354. + // The number of JS scripts injected.
  9355. + size_t num_js;
  9356. + // The number of blocked JS scripts injected.
  9357. + size_t num_blocking_js;
  9358. + // A map of extension ids to executing script paths.
  9359. + ExecutingScriptsMap executing_scripts;
  9360. + // A map of extension ids to injected stylesheet paths.
  9361. + ExecutingScriptsMap injected_stylesheets;
  9362. + // The elapsed time since the ScriptsRunInfo was constructed.
  9363. + base::ElapsedTimer timer;
  9364. +
  9365. + // Log information about a given script run. If |send_script_activity| is
  9366. + // true, this also informs the browser of the script run.
  9367. + void LogRun(bool send_script_activity);
  9368. +
  9369. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  9370. + const base::TimeDelta& elapsed);
  9371. +
  9372. + private:
  9373. + // The routinig id to use to notify the browser of any injections. Since the
  9374. + // frame may be deleted in injection, we don't hold on to a reference to it
  9375. + // directly.
  9376. + int routing_id_;
  9377. +
  9378. + // The run location at which injection is happening.
  9379. + UserScript::RunLocation run_location_;
  9380. +
  9381. + // The url of the frame, preserved for the same reason as the routing id.
  9382. + GURL frame_url_;
  9383. +};
  9384. +
  9385. +} // namespace extensions
  9386. +
  9387. +#endif // USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9388. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  9389. new file mode 100755
  9390. --- /dev/null
  9391. +++ b/components/user_scripts/renderer/user_script_injector.cc
  9392. @@ -0,0 +1,228 @@
  9393. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9394. +// Use of this source code is governed by a BSD-style license that can be
  9395. +// found in the LICENSE file.
  9396. +
  9397. +#include "user_script_injector.h"
  9398. +
  9399. +#include <tuple>
  9400. +#include <vector>
  9401. +
  9402. +#include "base/logging.h"
  9403. +#include "base/lazy_instance.h"
  9404. +#include "content/public/common/url_constants.h"
  9405. +#include "content/public/renderer/render_frame.h"
  9406. +#include "content/public/renderer/render_thread.h"
  9407. +#include "content/public/renderer/render_view.h"
  9408. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  9409. +#include "injection_host.h"
  9410. +#include "script_context.h"
  9411. +#include "scripts_run_info.h"
  9412. +#include "third_party/blink/public/web/web_document.h"
  9413. +#include "third_party/blink/public/web/web_local_frame.h"
  9414. +#include "third_party/blink/public/web/web_script_source.h"
  9415. +#include "ui/base/resource/resource_bundle.h"
  9416. +#include "url/gurl.h"
  9417. +
  9418. +namespace user_scripts {
  9419. +
  9420. +namespace {
  9421. +
  9422. +struct RoutingInfoKey {
  9423. + int routing_id;
  9424. + int script_id;
  9425. +
  9426. + RoutingInfoKey(int routing_id, int script_id)
  9427. + : routing_id(routing_id), script_id(script_id) {}
  9428. +
  9429. + bool operator<(const RoutingInfoKey& other) const {
  9430. + return std::tie(routing_id, script_id) <
  9431. + std::tie(other.routing_id, other.script_id);
  9432. + }
  9433. +};
  9434. +
  9435. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  9436. +
  9437. +// A map records whether a given |script_id| from a webview-added user script
  9438. +// is allowed to inject on the render of given |routing_id|.
  9439. +// Once a script is added, the decision of whether or not allowed to inject
  9440. +// won't be changed.
  9441. +// After removed by the webview, the user scipt will also be removed
  9442. +// from the render. Therefore, there won't be any query from the same
  9443. +// |script_id| and |routing_id| pair.
  9444. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  9445. +// LAZY_INSTANCE_INITIALIZER;
  9446. +
  9447. +// Greasemonkey API source that is injected with the scripts.
  9448. +struct GreasemonkeyApiJsString {
  9449. + GreasemonkeyApiJsString();
  9450. + blink::WebScriptSource GetSource() const;
  9451. +
  9452. + private:
  9453. + blink::WebString source_;
  9454. +};
  9455. +
  9456. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  9457. +// the GreasemonkeyApiJs resource.
  9458. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  9459. + std::string greasemonky_api_js(
  9460. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  9461. + IDR_GREASEMONKEY_API_JS));
  9462. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  9463. +}
  9464. +
  9465. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  9466. + return blink::WebScriptSource(source_);
  9467. +}
  9468. +
  9469. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  9470. + LAZY_INSTANCE_INITIALIZER;
  9471. +
  9472. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  9473. + const std::set<std::string>& injected_files) {
  9474. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  9475. + // Check if the script is already injected.
  9476. + if (injected_files.count(file->url().path()) == 0) {
  9477. + return true;
  9478. + }
  9479. + }
  9480. + return false;
  9481. +}
  9482. +
  9483. +} // namespace
  9484. +
  9485. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  9486. + UserScriptSet* script_list)
  9487. + : script_(script),
  9488. + user_script_set_(script_list),
  9489. + script_id_(script_->id()),
  9490. + user_script_set_observer_(this) {
  9491. + user_script_set_observer_.Observe(script_list);
  9492. +}
  9493. +
  9494. +UserScriptInjector::~UserScriptInjector() {
  9495. +}
  9496. +
  9497. +void UserScriptInjector::OnUserScriptsUpdated(
  9498. + const std::set<HostID>& changed_hosts,
  9499. + const UserScriptList& scripts) {
  9500. + // When user scripts are updated, all the old script pointers are invalidated.
  9501. + script_ = nullptr;
  9502. + // If the host causing this injection changed, then this injection
  9503. + // will be removed, and there's no guarantee the backing script still exists.
  9504. + // if (changed_hosts.count(host_id_) > 0)
  9505. + // return;
  9506. +
  9507. + for (const std::unique_ptr<UserScript>& script : scripts) {
  9508. + if (script->id() == script_id_) {
  9509. + script_ = script.get();
  9510. + break;
  9511. + }
  9512. + }
  9513. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  9514. + // should be guaranteed to exist.
  9515. + DCHECK(script_);
  9516. +}
  9517. +
  9518. +UserScript::InjectionType UserScriptInjector::script_type() const {
  9519. + return UserScript::CONTENT_SCRIPT;
  9520. +}
  9521. +
  9522. +bool UserScriptInjector::IsUserGesture() const {
  9523. + return false;
  9524. +}
  9525. +
  9526. +bool UserScriptInjector::ExpectsResults() const {
  9527. + return false;
  9528. +}
  9529. +
  9530. +absl::optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  9531. + return absl::nullopt;
  9532. +}
  9533. +
  9534. +const absl::optional<std::string> UserScriptInjector::GetInjectionKey() const {
  9535. + return absl::nullopt;
  9536. +}
  9537. +
  9538. +bool UserScriptInjector::ShouldInjectJs(
  9539. + UserScript::RunLocation run_location,
  9540. + const std::set<std::string>& executing_scripts) const {
  9541. + return script_ && script_->run_location() == run_location &&
  9542. + !script_->js_scripts().empty() &&
  9543. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  9544. +}
  9545. +
  9546. +bool UserScriptInjector::ShouldInjectCss(
  9547. + UserScript::RunLocation run_location,
  9548. + const std::set<std::string>& injected_stylesheets) const {
  9549. + return script_ && run_location == UserScript::DOCUMENT_START &&
  9550. + !script_->css_scripts().empty() &&
  9551. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  9552. +}
  9553. +
  9554. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  9555. + UserScript::RunLocation run_location,
  9556. + std::set<std::string>* executing_scripts,
  9557. + size_t* num_injected_js_scripts) const {
  9558. + DCHECK(script_);
  9559. + std::vector<blink::WebScriptSource> sources;
  9560. +
  9561. + DCHECK_EQ(script_->run_location(), run_location);
  9562. +
  9563. + const UserScript::FileList& js_scripts = script_->js_scripts();
  9564. + sources.reserve(js_scripts.size() +
  9565. + (script_->emulate_greasemonkey() ? 1 : 0));
  9566. + // Emulate Greasemonkey API for scripts that were converted to extension
  9567. + // user scripts.
  9568. + if (script_->emulate_greasemonkey())
  9569. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  9570. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  9571. + const GURL& script_url = file->url();
  9572. + // Check if the script is already injected.
  9573. + if (executing_scripts->count(script_url.path()) != 0)
  9574. + continue;
  9575. +
  9576. + sources.push_back(blink::WebScriptSource(
  9577. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  9578. + script_url));
  9579. +
  9580. + (*num_injected_js_scripts) += 1;
  9581. + executing_scripts->insert(script_url.path());
  9582. + }
  9583. +
  9584. + return sources;
  9585. +}
  9586. +
  9587. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  9588. + UserScript::RunLocation run_location,
  9589. + std::set<std::string>* injected_stylesheets,
  9590. + size_t* num_injected_stylesheets) const {
  9591. + DCHECK(script_);
  9592. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  9593. +
  9594. + std::vector<blink::WebString> sources;
  9595. +
  9596. + const UserScript::FileList& css_scripts = script_->css_scripts();
  9597. + sources.reserve(css_scripts.size());
  9598. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  9599. + const std::string& stylesheet_path = file->url().path();
  9600. + // Check if the stylesheet is already injected.
  9601. + if (injected_stylesheets->count(stylesheet_path) != 0)
  9602. + continue;
  9603. +
  9604. + sources.push_back(user_script_set_->GetCssSource(*file));
  9605. + (*num_injected_stylesheets) += 1;
  9606. + injected_stylesheets->insert(stylesheet_path);
  9607. + }
  9608. + return sources;
  9609. +}
  9610. +
  9611. +void UserScriptInjector::OnInjectionComplete(
  9612. + std::unique_ptr<base::Value> execution_result,
  9613. + UserScript::RunLocation run_location,
  9614. + content::RenderFrame* render_frame) {}
  9615. +
  9616. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  9617. + content::RenderFrame* render_frame) {
  9618. +}
  9619. +
  9620. +} // namespace extensions
  9621. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  9622. new file mode 100755
  9623. --- /dev/null
  9624. +++ b/components/user_scripts/renderer/user_script_injector.h
  9625. @@ -0,0 +1,86 @@
  9626. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9627. +// Use of this source code is governed by a BSD-style license that can be
  9628. +// found in the LICENSE file.
  9629. +
  9630. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9631. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9632. +
  9633. +#include <memory>
  9634. +#include <string>
  9635. +
  9636. +#include "base/values.h"
  9637. +#include "base/scoped_observation.h"
  9638. +#include "../common/user_script.h"
  9639. +#include "script_injection.h"
  9640. +#include "user_script_set.h"
  9641. +
  9642. +class InjectionHost;
  9643. +
  9644. +namespace blink {
  9645. +class WebLocalFrame;
  9646. +}
  9647. +
  9648. +namespace user_scripts {
  9649. +
  9650. +// A ScriptInjector for UserScripts.
  9651. +class UserScriptInjector : public ScriptInjector,
  9652. + public UserScriptSet::Observer {
  9653. + public:
  9654. + UserScriptInjector(const UserScriptInjector&) = delete;
  9655. + UserScriptInjector& operator=(const UserScriptInjector&) = delete;
  9656. + UserScriptInjector(const UserScript* user_script,
  9657. + UserScriptSet* user_script_set);
  9658. + ~UserScriptInjector() override;
  9659. +
  9660. + private:
  9661. + // UserScriptSet::Observer implementation.
  9662. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9663. + const UserScriptList& scripts) override;
  9664. +
  9665. + // ScriptInjector implementation.
  9666. + UserScript::InjectionType script_type() const override;
  9667. + bool IsUserGesture() const override;
  9668. + absl::optional<CSSOrigin> GetCssOrigin() const override;
  9669. + const absl::optional<std::string> GetInjectionKey() const override;
  9670. + bool ExpectsResults() const override;
  9671. + bool ShouldInjectJs(
  9672. + UserScript::RunLocation run_location,
  9673. + const std::set<std::string>& executing_scripts) const override;
  9674. + bool ShouldInjectCss(
  9675. + UserScript::RunLocation run_location,
  9676. + const std::set<std::string>& injected_stylesheets) const override;
  9677. + std::vector<blink::WebScriptSource> GetJsSources(
  9678. + UserScript::RunLocation run_location,
  9679. + std::set<std::string>* executing_scripts,
  9680. + size_t* num_injected_js_scripts) const override;
  9681. + std::vector<blink::WebString> GetCssSources(
  9682. + UserScript::RunLocation run_location,
  9683. + std::set<std::string>* injected_stylesheets,
  9684. + size_t* num_injected_stylesheets) const override;
  9685. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  9686. + UserScript::RunLocation run_location,
  9687. + content::RenderFrame* render_frame) override;
  9688. + void OnWillNotInject(InjectFailureReason reason,
  9689. + content::RenderFrame* render_frame) override;
  9690. +
  9691. + // The associated user script. Owned by the UserScriptInjector that created
  9692. + // this object.
  9693. + const UserScript* script_;
  9694. +
  9695. + // The UserScriptSet that eventually owns the UserScript this
  9696. + // UserScriptInjector points to.
  9697. + // Outlives |this|.
  9698. + UserScriptSet* const user_script_set_;
  9699. +
  9700. + // The id of the associated user script. We cache this because when we update
  9701. + // the |script_| associated with this injection, the old referance may be
  9702. + // deleted.
  9703. + int script_id_;
  9704. +
  9705. + base::ScopedObservation<UserScriptSet, UserScriptSet::Observer>
  9706. + user_script_set_observer_{this};
  9707. +};
  9708. +
  9709. +} // namespace extensions
  9710. +
  9711. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9712. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  9713. new file mode 100755
  9714. --- /dev/null
  9715. +++ b/components/user_scripts/renderer/user_script_set.cc
  9716. @@ -0,0 +1,262 @@
  9717. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9718. +// Use of this source code is governed by a BSD-style license that can be
  9719. +// found in the LICENSE file.
  9720. +
  9721. +#include "user_script_set.h"
  9722. +
  9723. +#include <stddef.h>
  9724. +
  9725. +#include <utility>
  9726. +
  9727. +#include "base/logging.h"
  9728. +#include "base/debug/alias.h"
  9729. +#include "base/memory/ref_counted.h"
  9730. +#include "base/strings/strcat.h"
  9731. +#include "content/public/common/url_constants.h"
  9732. +#include "content/public/renderer/render_frame.h"
  9733. +#include "content/public/renderer/render_thread.h"
  9734. +#include "injection_host.h"
  9735. +#include "script_context.h"
  9736. +#include "script_injection.h"
  9737. +#include "user_script_injector.h"
  9738. +#include "web_ui_injection_host.h"
  9739. +#include "third_party/blink/public/web/web_document.h"
  9740. +#include "third_party/blink/public/web/web_local_frame.h"
  9741. +#include "url/gurl.h"
  9742. +#include "../common/user_scripts_features.h"
  9743. +
  9744. +namespace user_scripts {
  9745. +
  9746. +namespace {
  9747. +
  9748. +// These two strings are injected before and after the Greasemonkey API and
  9749. +// user script to wrap it in an anonymous scope.
  9750. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  9751. +const char kUserScriptTail[] = "\n})(window);";
  9752. +// Maximum number of total content scripts we allow (across all extensions).
  9753. +// The limit exists to diagnose https://crbug.com/723381. The number is
  9754. +// arbitrarily chosen.
  9755. +// TODO(lazyboy): Remove when the bug is fixed.
  9756. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  9757. +
  9758. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  9759. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  9760. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  9761. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  9762. + data_source_url.spec());
  9763. + }
  9764. +
  9765. + return data_source_url;
  9766. +}
  9767. +
  9768. +} // namespace
  9769. +
  9770. +UserScriptSet::UserScriptSet() {}
  9771. +
  9772. +UserScriptSet::~UserScriptSet() {
  9773. +}
  9774. +
  9775. +void UserScriptSet::AddObserver(Observer* observer) {
  9776. + observers_.AddObserver(observer);
  9777. +}
  9778. +
  9779. +void UserScriptSet::RemoveObserver(Observer* observer) {
  9780. + observers_.RemoveObserver(observer);
  9781. +}
  9782. +
  9783. +void UserScriptSet::GetInjections(
  9784. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9785. + content::RenderFrame* render_frame,
  9786. + int tab_id,
  9787. + UserScript::RunLocation run_location,
  9788. + bool log_activity) {
  9789. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  9790. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  9791. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  9792. + script.get(), render_frame, tab_id, run_location, document_url,
  9793. + /* is_declarative, */ log_activity);
  9794. + if (injection.get())
  9795. + injections->push_back(std::move(injection));
  9796. + }
  9797. +}
  9798. +
  9799. +bool UserScriptSet::UpdateUserScripts(
  9800. + base::ReadOnlySharedMemoryRegion shared_memory,
  9801. + const std::set<HostID>& changed_hosts,
  9802. + bool whitelisted_only) {
  9803. + bool only_inject_incognito = false;
  9804. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  9805. +
  9806. + // Create the shared memory mapping.
  9807. + shared_memory_mapping_ = shared_memory.Map();
  9808. + if (!shared_memory.IsValid())
  9809. + return false;
  9810. +
  9811. + // First get the size of the memory block.
  9812. + const base::Pickle::Header* pickle_header =
  9813. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  9814. + if (!pickle_header)
  9815. + return false;
  9816. +
  9817. + // Now read in the rest of the block.
  9818. + size_t pickle_size =
  9819. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  9820. +
  9821. + // Unpickle scripts.
  9822. + uint32_t num_scripts = 0;
  9823. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9824. + if (!memory.size())
  9825. + return false;
  9826. +
  9827. + base::Pickle pickle(memory.data(), pickle_size);
  9828. + base::PickleIterator iter(pickle);
  9829. + base::debug::Alias(&pickle_size);
  9830. + CHECK(iter.ReadUInt32(&num_scripts));
  9831. +
  9832. + // Sometimes the shared memory contents seem to be corrupted
  9833. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9834. + // scripts so that we don't add OOM noise to crash reports.
  9835. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9836. +
  9837. + scripts_.clear();
  9838. + script_sources_.clear();
  9839. + scripts_.reserve(num_scripts);
  9840. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9841. + std::unique_ptr<UserScript> script(new UserScript());
  9842. + script->Unpickle(pickle, &iter);
  9843. +
  9844. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9845. + // cleared up when the last renderer or browser process drops their
  9846. + // reference to the shared memory.
  9847. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9848. + const char* body = NULL;
  9849. + int body_length = 0;
  9850. + CHECK(iter.ReadData(&body, &body_length));
  9851. + script->js_scripts()[j]->set_external_content(
  9852. + base::StringPiece(body, body_length));
  9853. + }
  9854. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9855. + const char* body = NULL;
  9856. + int body_length = 0;
  9857. + CHECK(iter.ReadData(&body, &body_length));
  9858. + script->css_scripts()[j]->set_external_content(
  9859. + base::StringPiece(body, body_length));
  9860. + }
  9861. +
  9862. + if (only_inject_incognito && !script->is_incognito_enabled())
  9863. + continue; // This script shouldn't run in an incognito tab.
  9864. +
  9865. + scripts_.push_back(std::move(script));
  9866. + }
  9867. +
  9868. + for (auto& observer : observers_)
  9869. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9870. + return true;
  9871. +}
  9872. +
  9873. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9874. + scripts_.push_back(std::move(script));
  9875. +}
  9876. +
  9877. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9878. + const UserScript* script,
  9879. + content::RenderFrame* render_frame,
  9880. + int tab_id,
  9881. + UserScript::RunLocation run_location,
  9882. + const GURL& document_url,
  9883. + //bool is_declarative,
  9884. + bool log_activity) {
  9885. + std::unique_ptr<ScriptInjection> injection;
  9886. + std::unique_ptr<const InjectionHost> injection_host;
  9887. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9888. +
  9889. + const HostID& host_id = script->host_id();
  9890. + injection_host.reset(new WebUIInjectionHost(host_id));
  9891. +
  9892. + GURL effective_document_url =
  9893. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9894. + web_frame, document_url, script->match_origin_as_fallback());
  9895. +
  9896. + bool is_subframe = web_frame->Parent();
  9897. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9898. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9899. + LOG(INFO) << "UserScripts: Match name=" << script->name() <<
  9900. + " id=" << script->host_id().id() <<
  9901. + " url=" << effective_document_url.spec();
  9902. + return injection;
  9903. + }
  9904. +
  9905. + std::unique_ptr<ScriptInjector> injector(
  9906. + new UserScriptInjector(script, this));
  9907. +
  9908. + bool inject_css = !script->css_scripts().empty() &&
  9909. + run_location == UserScript::DOCUMENT_START;
  9910. + bool inject_js =
  9911. + !script->js_scripts().empty() && script->run_location() == run_location;
  9912. + if (inject_css || inject_js) {
  9913. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9914. + std::move(injection_host), run_location,
  9915. + log_activity));
  9916. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9917. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9918. + "url=" << effective_document_url.spec();
  9919. + } else {
  9920. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9921. + if (script->run_location() != run_location)
  9922. + LOG(INFO) << "UserScripts: run location for name=" << script->name() <<
  9923. + " id=" << script->host_id().id() <<
  9924. + " current " << run_location <<
  9925. + " need " << script->run_location();
  9926. + else
  9927. + LOG(INFO) << "UserScripts: Match but no run name=" << script->name() <<
  9928. + " id=" << script->host_id().id() <<
  9929. + " url=" << effective_document_url.spec();
  9930. + }
  9931. + }
  9932. + return injection;
  9933. +}
  9934. +
  9935. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9936. + bool emulate_greasemonkey) {
  9937. + const GURL& url = file.url();
  9938. + auto iter = script_sources_.find(url);
  9939. + if (iter != script_sources_.end()) {
  9940. + return iter->second;
  9941. + }
  9942. +
  9943. + base::StringPiece script_content = file.GetContent();
  9944. + blink::WebString source;
  9945. + if (emulate_greasemonkey) {
  9946. + // We add this dumb function wrapper for user scripts to emulate what
  9947. + // Greasemonkey does. |script_content| becomes:
  9948. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9949. + std::string content =
  9950. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9951. + source = blink::WebString::FromUTF8(content);
  9952. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9953. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9954. + } else {
  9955. + source = blink::WebString::FromUTF8(script_content.data(),
  9956. + script_content.length());
  9957. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9958. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9959. + }
  9960. + script_sources_[url] = source;
  9961. + return source;
  9962. +}
  9963. +
  9964. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9965. + const GURL& url = file.url();
  9966. + auto iter = script_sources_.find(url);
  9967. + if (iter != script_sources_.end())
  9968. + return iter->second;
  9969. +
  9970. + base::StringPiece script_content = file.GetContent();
  9971. + return script_sources_
  9972. + .insert(std::make_pair(
  9973. + url, blink::WebString::FromUTF8(script_content.data(),
  9974. + script_content.length())))
  9975. + .first->second;
  9976. +}
  9977. +
  9978. +} // namespace extensions
  9979. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9980. new file mode 100755
  9981. --- /dev/null
  9982. +++ b/components/user_scripts/renderer/user_script_set.h
  9983. @@ -0,0 +1,101 @@
  9984. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9985. +// Use of this source code is governed by a BSD-style license that can be
  9986. +// found in the LICENSE file.
  9987. +
  9988. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9989. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9990. +
  9991. +#include <map>
  9992. +#include <memory>
  9993. +#include <set>
  9994. +#include <string>
  9995. +#include <vector>
  9996. +
  9997. +#include "base/memory/read_only_shared_memory_region.h"
  9998. +#include "base/observer_list.h"
  9999. +#include "../common/user_script.h"
  10000. +#include "third_party/blink/public/platform/web_string.h"
  10001. +
  10002. +class GURL;
  10003. +
  10004. +namespace content {
  10005. +class RenderFrame;
  10006. +}
  10007. +
  10008. +namespace user_scripts {
  10009. +class ScriptInjection;
  10010. +
  10011. +// The UserScriptSet is a collection of UserScripts which knows how to update
  10012. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  10013. +// inject on a page.
  10014. +class UserScriptSet {
  10015. + public:
  10016. + UserScriptSet(const UserScriptSet&) = delete;
  10017. + UserScriptSet& operator=(const UserScriptSet&) = delete;
  10018. + class Observer {
  10019. + public:
  10020. + // Called when the set of user scripts is updated. |changed_hosts| contains
  10021. + // the hosts whose scripts have been altered. Note that *all* script objects
  10022. + // are invalidated, even if they aren't in |changed_hosts|.
  10023. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  10024. + const UserScriptList& scripts) = 0;
  10025. + };
  10026. +
  10027. + UserScriptSet();
  10028. + ~UserScriptSet();
  10029. +
  10030. + // Adds or removes observers.
  10031. + void AddObserver(Observer* observer);
  10032. + void RemoveObserver(Observer* observer);
  10033. + void AddScript(std::unique_ptr<UserScript> script);
  10034. +
  10035. + // Append any ScriptInjections that should run on the given |render_frame| and
  10036. + // |tab_id|, at the given |run_location|, to |injections|.
  10037. + // |extensions| is passed in to verify the corresponding extension is still
  10038. + // valid.
  10039. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10040. + content::RenderFrame* render_frame,
  10041. + int tab_id,
  10042. + UserScript::RunLocation run_location,
  10043. + bool log_activity);
  10044. +
  10045. + // Updates scripts given the shared memory region containing user scripts.
  10046. + // Returns true if the scripts were successfully updated.
  10047. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  10048. + const std::set<HostID>& changed_hosts,
  10049. + bool whitelisted_only);
  10050. +
  10051. + // Returns the contents of a script file.
  10052. + // Note that copying is cheap as this uses WebString.
  10053. + blink::WebString GetJsSource(const UserScript::File& file,
  10054. + bool emulate_greasemonkey);
  10055. + blink::WebString GetCssSource(const UserScript::File& file);
  10056. +
  10057. + private:
  10058. + // Returns a new ScriptInjection for the given |script| to execute in the
  10059. + // |render_frame|, or NULL if the script should not execute.
  10060. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  10061. + const UserScript* script,
  10062. + content::RenderFrame* render_frame,
  10063. + int tab_id,
  10064. + UserScript::RunLocation run_location,
  10065. + const GURL& document_url,
  10066. + //bool is_declarative,
  10067. + bool log_activity);
  10068. +
  10069. + // Shared memory mapping containing raw script data.
  10070. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  10071. +
  10072. + // The UserScripts this injector manages.
  10073. + UserScriptList scripts_;
  10074. +
  10075. + // Map of user script file url -> source.
  10076. + std::map<GURL, blink::WebString> script_sources_;
  10077. +
  10078. + // The associated observers.
  10079. + base::ObserverList<Observer>::Unchecked observers_;
  10080. +};
  10081. +
  10082. +} // namespace extensions
  10083. +
  10084. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  10085. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  10086. new file mode 100755
  10087. --- /dev/null
  10088. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  10089. @@ -0,0 +1,77 @@
  10090. +#include "user_script_set_manager.h"
  10091. +
  10092. +#include "base/logging.h"
  10093. +#include "content/public/renderer/render_thread.h"
  10094. +#include "../common/host_id.h"
  10095. +#include "../common/extension_messages.h"
  10096. +#include "../common/user_scripts_features.h"
  10097. +#include "user_script_set.h"
  10098. +
  10099. +namespace user_scripts {
  10100. +
  10101. +UserScriptSetManager::UserScriptSetManager() {
  10102. + content::RenderThread::Get()->AddObserver(this);
  10103. +}
  10104. +
  10105. +UserScriptSetManager::~UserScriptSetManager() {
  10106. +}
  10107. +
  10108. +void UserScriptSetManager::AddObserver(Observer* observer) {
  10109. + observers_.AddObserver(observer);
  10110. +}
  10111. +
  10112. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  10113. + observers_.RemoveObserver(observer);
  10114. +}
  10115. +
  10116. +bool UserScriptSetManager::OnControlMessageReceived(
  10117. + const IPC::Message& message) {
  10118. + bool handled = true;
  10119. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  10120. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  10121. + IPC_MESSAGE_UNHANDLED(handled = false)
  10122. + IPC_END_MESSAGE_MAP()
  10123. + return handled;
  10124. +}
  10125. +
  10126. +void UserScriptSetManager::GetAllInjections(
  10127. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10128. + content::RenderFrame* render_frame,
  10129. + int tab_id,
  10130. + UserScript::RunLocation run_location) {
  10131. +
  10132. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10133. + LOG(INFO) << "UserScripts: GetAllInjections";
  10134. +
  10135. + // static_scripts_ is UserScriptSet
  10136. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  10137. + activity_logging_enabled_);
  10138. +}
  10139. +
  10140. +void UserScriptSetManager::OnUpdateUserScripts(
  10141. + base::ReadOnlySharedMemoryRegion shared_memory) {
  10142. + if (!shared_memory.IsValid()) {
  10143. + NOTREACHED() << "Bad scripts handle";
  10144. + return;
  10145. + }
  10146. +
  10147. + UserScriptSet* scripts = NULL;
  10148. + scripts = &static_scripts_;
  10149. +
  10150. + DCHECK(scripts);
  10151. +
  10152. + // If no hosts are included in the set, that indicates that all
  10153. + // hosts were updated. Add them all to the set so that observers and
  10154. + // individual UserScriptSets don't need to know this detail.
  10155. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  10156. + std::set<HostID> all_hosts;
  10157. + const std::set<HostID>* effective_hosts = &all_hosts;
  10158. +
  10159. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  10160. + false /*whitelisted_only*/)) {
  10161. + for (auto& observer : observers_)
  10162. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  10163. + }
  10164. +}
  10165. +
  10166. +}
  10167. \ No newline at end of file
  10168. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  10169. new file mode 100755
  10170. --- /dev/null
  10171. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  10172. @@ -0,0 +1,61 @@
  10173. +#ifndef USERSCRIPTS_RENDER_SET_MANAGER_H_
  10174. +#define USERSCRIPTS_RENDER_SET_MANAGER_H_
  10175. +
  10176. +#include <map>
  10177. +#include <set>
  10178. +#include <string>
  10179. +#include <vector>
  10180. +
  10181. +#include "base/memory/read_only_shared_memory_region.h"
  10182. +#include "base/observer_list.h"
  10183. +#include "content/public/renderer/render_thread_observer.h"
  10184. +#include "../common/host_id.h"
  10185. +#include "user_script_set.h"
  10186. +#include "script_injection.h"
  10187. +
  10188. +namespace user_scripts {
  10189. +
  10190. +class UserScriptSetManager : public content::RenderThreadObserver {
  10191. + public:
  10192. + class Observer {
  10193. + public:
  10194. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  10195. + };
  10196. +
  10197. + UserScriptSetManager();
  10198. +
  10199. + ~UserScriptSetManager() override;
  10200. +
  10201. + void AddObserver(Observer* observer);
  10202. + void RemoveObserver(Observer* observer);
  10203. +
  10204. + // Append all injections from |static_scripts| and each of
  10205. + // |programmatic_scripts_| to |injections|.
  10206. + void GetAllInjections(
  10207. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10208. + content::RenderFrame* render_frame,
  10209. + int tab_id,
  10210. + UserScript::RunLocation run_location);
  10211. +
  10212. +private:
  10213. + // content::RenderThreadObserver implementation.
  10214. + bool OnControlMessageReceived(const IPC::Message& message) override;
  10215. +
  10216. + base::ObserverList<Observer>::Unchecked observers_;
  10217. +
  10218. + // Handle the UpdateUserScripts extension message.
  10219. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  10220. + //, const HostID& host_id,
  10221. + //const std::set<HostID>& changed_hosts,
  10222. + //bool whitelisted_only);
  10223. +
  10224. + // Scripts statically defined in extension manifests.
  10225. + UserScriptSet static_scripts_;
  10226. +
  10227. + // Whether or not dom activity should be logged for scripts injected.
  10228. + bool activity_logging_enabled_ = false;
  10229. +};
  10230. +
  10231. +}
  10232. +
  10233. +#endif
  10234. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10235. new file mode 100755
  10236. --- /dev/null
  10237. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10238. @@ -0,0 +1,36 @@
  10239. +#include "user_scripts_dispatcher.h"
  10240. +
  10241. +#include <stddef.h>
  10242. +
  10243. +#include <algorithm>
  10244. +#include <memory>
  10245. +#include <utility>
  10246. +
  10247. +#include "content/public/renderer/render_thread.h"
  10248. +#include "extension_frame_helper.h"
  10249. +
  10250. +namespace user_scripts {
  10251. +
  10252. +// ex ChromeExtensionsDispatcherDelegate
  10253. +UserScriptsDispatcher::UserScriptsDispatcher()
  10254. + : user_script_set_manager_observer_(this) {
  10255. + user_script_set_manager_.reset(new UserScriptSetManager());
  10256. + script_injection_manager_.reset(
  10257. + new ScriptInjectionManager(user_script_set_manager_.get()));
  10258. + user_script_set_manager_observer_.Observe(user_script_set_manager_.get());
  10259. +}
  10260. +
  10261. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  10262. +}
  10263. +
  10264. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  10265. +}
  10266. +
  10267. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  10268. +}
  10269. +
  10270. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  10271. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  10272. +}
  10273. +
  10274. +}
  10275. \ No newline at end of file
  10276. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10277. new file mode 100755
  10278. --- /dev/null
  10279. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10280. @@ -0,0 +1,49 @@
  10281. +#ifndef USERSCRIPTS_RENDER_DISPATCHER_H_
  10282. +#define USERSCRIPTS_RENDER_DISPATCHER_H_
  10283. +
  10284. +#include "user_script_set_manager.h"
  10285. +#include "script_injection_manager.h"
  10286. +
  10287. +#include <stdint.h>
  10288. +
  10289. +#include <map>
  10290. +#include <memory>
  10291. +#include <set>
  10292. +#include <string>
  10293. +#include <utility>
  10294. +#include <vector>
  10295. +
  10296. +#include "base/scoped_observation.h"
  10297. +#include "content/public/renderer/render_thread_observer.h"
  10298. +#include "content/public/renderer/render_thread.h"
  10299. +#include "../common/host_id.h"
  10300. +#include "user_script_set_manager.h"
  10301. +#include "script_injection.h"
  10302. +
  10303. +namespace user_scripts {
  10304. +
  10305. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  10306. + public UserScriptSetManager::Observer {
  10307. +
  10308. + public:
  10309. + UserScriptsDispatcher(const UserScriptsDispatcher&) = delete;
  10310. + UserScriptsDispatcher& operator=(const UserScriptsDispatcher&) = delete;
  10311. + explicit UserScriptsDispatcher();
  10312. + ~UserScriptsDispatcher() override;
  10313. +
  10314. + void OnRenderThreadStarted(content::RenderThread* thread);
  10315. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  10316. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  10317. +
  10318. + private:
  10319. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  10320. +
  10321. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  10322. +
  10323. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  10324. + user_script_set_manager_observer_{this};
  10325. +};
  10326. +
  10327. +}
  10328. +
  10329. +#endif
  10330. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10331. new file mode 100755
  10332. --- /dev/null
  10333. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10334. @@ -0,0 +1,105 @@
  10335. +#include "user_scripts_renderer_client.h"
  10336. +
  10337. +#include <memory>
  10338. +#include <utility>
  10339. +
  10340. +#include "base/logging.h"
  10341. +#include "base/lazy_instance.h"
  10342. +#include "content/public/renderer/render_frame.h"
  10343. +#include "content/public/renderer/render_thread.h"
  10344. +#include "content/public/renderer/render_frame_visitor.h"
  10345. +#include "chrome/renderer/chrome_render_thread_observer.h"
  10346. +
  10347. +#include "../common/user_scripts_features.h"
  10348. +#include "user_scripts_dispatcher.h"
  10349. +#include "extension_frame_helper.h"
  10350. +
  10351. +namespace user_scripts {
  10352. +
  10353. +// was ChromeExtensionsRendererClient
  10354. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  10355. +
  10356. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  10357. +
  10358. +// static
  10359. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  10360. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  10361. + LAZY_INSTANCE_INITIALIZER;
  10362. + return client.Pointer();
  10363. +}
  10364. +
  10365. +void UserScriptsRendererClient::RenderThreadStarted() {
  10366. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10367. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  10368. +
  10369. + content::RenderThread* thread = content::RenderThread::Get();
  10370. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  10371. +
  10372. + dispatcher_->OnRenderThreadStarted(thread);
  10373. + thread->AddObserver(dispatcher_.get());
  10374. +}
  10375. +
  10376. +void UserScriptsRendererClient::ConfigurationUpdated() {
  10377. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10378. + LOG(INFO) << "UserScripts: Configuration Updated";
  10379. +
  10380. + struct WatchFrame : public content::RenderFrameVisitor {
  10381. + bool Visit(content::RenderFrame* frame) override {
  10382. + if (frame)
  10383. + UserScriptsRendererClient::GetInstance()->RenderFrameCreated(frame, NULL);
  10384. + return true; // Continue visiting.
  10385. + }
  10386. + };
  10387. + WatchFrame visitor = {};
  10388. + content::RenderFrame::ForEach(&visitor);
  10389. +}
  10390. +
  10391. +void UserScriptsRendererClient::RenderFrameCreated(
  10392. + content::RenderFrame* render_frame,
  10393. + service_manager::BinderRegistry* registry) {
  10394. +
  10395. + auto params = ChromeRenderThreadObserver::GetDynamicParams();
  10396. + enabled_ = params.allow_userscript;
  10397. + if (!enabled_) return;
  10398. +
  10399. + if (loaded_ == false) {
  10400. + loaded_ = true;
  10401. + new user_scripts::ExtensionFrameHelper(render_frame);
  10402. + dispatcher_->OnRenderFrameCreated(render_frame);
  10403. + }
  10404. +}
  10405. +
  10406. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  10407. + if (!enabled_ || !loaded_) return;
  10408. +
  10409. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10410. + if (!frame_helper)
  10411. + return; // The frame is invisible to user scripts.
  10412. +
  10413. + frame_helper->RunScriptsAtDocumentStart();
  10414. + // |frame_helper| and |render_frame| might be dead by now.
  10415. +}
  10416. +
  10417. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  10418. + if (!enabled_ || !loaded_) return;
  10419. +
  10420. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10421. + if (!frame_helper)
  10422. + return; // The frame is invisible to user scripts.
  10423. +
  10424. + frame_helper->RunScriptsAtDocumentEnd();
  10425. + // |frame_helper| and |render_frame| might be dead by now.
  10426. +}
  10427. +
  10428. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  10429. + if (!enabled_ || !loaded_) return;
  10430. +
  10431. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10432. + if (!frame_helper)
  10433. + return; // The frame is invisible to user scripts.
  10434. +
  10435. + frame_helper->RunScriptsAtDocumentIdle();
  10436. + // |frame_helper| and |render_frame| might be dead by now.
  10437. +}
  10438. +
  10439. +}
  10440. \ No newline at end of file
  10441. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10442. new file mode 100755
  10443. --- /dev/null
  10444. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10445. @@ -0,0 +1,37 @@
  10446. +#ifndef USERSCRIPTS_RENDER_CLIENT_H_
  10447. +#define USERSCRIPTS_RENDER_CLIENT_H_
  10448. +
  10449. +#include <memory>
  10450. +#include <string>
  10451. +
  10452. +#include "user_scripts_dispatcher.h"
  10453. +#include "services/service_manager/public/cpp/binder_registry.h"
  10454. +
  10455. +namespace user_scripts {
  10456. +
  10457. +class UserScriptsRendererClient {
  10458. + public:
  10459. + UserScriptsRendererClient(const UserScriptsRendererClient&) = delete;
  10460. + UserScriptsRendererClient& operator=(const UserScriptsRendererClient&) = delete;
  10461. + UserScriptsRendererClient();
  10462. + ~UserScriptsRendererClient();
  10463. +
  10464. + static UserScriptsRendererClient* GetInstance();
  10465. +
  10466. + void RenderThreadStarted();
  10467. + void ConfigurationUpdated();
  10468. + void RenderFrameCreated(content::RenderFrame* render_frame,
  10469. + service_manager::BinderRegistry* registry);
  10470. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  10471. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  10472. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  10473. +
  10474. + private:
  10475. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  10476. + bool enabled_ = false;
  10477. + bool loaded_ = false;
  10478. +};
  10479. +
  10480. +}
  10481. +
  10482. +#endif
  10483. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  10484. new file mode 100755
  10485. --- /dev/null
  10486. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  10487. @@ -0,0 +1,40 @@
  10488. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10489. +// Use of this source code is governed by a BSD-style license that can be
  10490. +// found in the LICENSE file.
  10491. +
  10492. +#include "web_ui_injection_host.h"
  10493. +#include "base/no_destructor.h"
  10494. +
  10495. +namespace {
  10496. +
  10497. +// The default secure CSP to be used in order to prevent remote scripts.
  10498. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  10499. +
  10500. +}
  10501. +
  10502. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  10503. + : InjectionHost(host_id),
  10504. + url_(host_id.id()) {
  10505. +}
  10506. +
  10507. +WebUIInjectionHost::~WebUIInjectionHost() {
  10508. +}
  10509. +
  10510. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  10511. + // Use the main world CSP.
  10512. + // return nullptr;
  10513. +
  10514. + // The isolated world will use its own CSP which blocks remotely hosted
  10515. + // code.
  10516. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  10517. + kDefaultSecureCSP);
  10518. + return default_isolated_world_csp.get();
  10519. +}
  10520. +
  10521. +const GURL& WebUIInjectionHost::url() const {
  10522. + return url_;
  10523. +}
  10524. +
  10525. +const std::string& WebUIInjectionHost::name() const {
  10526. + return id().id();
  10527. +}
  10528. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  10529. new file mode 100755
  10530. --- /dev/null
  10531. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  10532. @@ -0,0 +1,27 @@
  10533. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10534. +// Use of this source code is governed by a BSD-style license that can be
  10535. +// found in the LICENSE file.
  10536. +
  10537. +#ifndef USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10538. +#define USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10539. +
  10540. +#include "injection_host.h"
  10541. +
  10542. +class WebUIInjectionHost : public InjectionHost {
  10543. + public:
  10544. + WebUIInjectionHost(const WebUIInjectionHost&) = delete;
  10545. + WebUIInjectionHost& operator=(const WebUIInjectionHost&) = delete;
  10546. + WebUIInjectionHost(const HostID& host_id);
  10547. + ~WebUIInjectionHost() override;
  10548. +
  10549. + private:
  10550. + // InjectionHost:
  10551. + const std::string* GetContentSecurityPolicy() const override;
  10552. + const GURL& url() const override;
  10553. + const std::string& name() const override;
  10554. +
  10555. + private:
  10556. + GURL url_;
  10557. +};
  10558. +
  10559. +#endif // USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10560. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  10561. new file mode 100755
  10562. --- /dev/null
  10563. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  10564. @@ -0,0 +1,55 @@
  10565. +<?xml version="1.0" encoding="utf-8"?>
  10566. +<grit-part>
  10567. +
  10568. + <!-- Preferences -->
  10569. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  10570. + desc="."
  10571. + formatter_data="android_java">
  10572. + User Scripts
  10573. + </message>
  10574. +
  10575. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  10576. + Activate User Scripts
  10577. + </message>
  10578. +
  10579. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10580. + ON
  10581. + </message>
  10582. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10583. + OFF
  10584. + </message>
  10585. +
  10586. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10587. + Add script
  10588. + </message>
  10589. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  10590. + Experimental support for Greasemonkey-style user scripts.
  10591. + </message>
  10592. +
  10593. + <message name="IDS_SCRIPTS_ITEM_VERSION" desc="." formatter_data="android_java">
  10594. + Version:
  10595. + </message>
  10596. + <message name="IDS_SCRIPTS_ITEM_FILENAME" desc="." formatter_data="android_java">
  10597. + File:
  10598. + </message>
  10599. + <message name="IDS_SCRIPTS_ITEM_URL" desc="." formatter_data="android_java">
  10600. + Url:
  10601. + </message>
  10602. +
  10603. + <message name="IDS_SCRIPTS_VIEW_SOURCE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10604. + View source
  10605. + </message>
  10606. +
  10607. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10608. + Only install user scripts that you have verified are secure, user scripts can steal your credentials and data.
  10609. +
  10610. +Do you want to install <ph name="FILE">%s</ph>?
  10611. + </message>
  10612. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10613. + Yes
  10614. + </message>
  10615. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10616. + No
  10617. + </message>
  10618. +
  10619. +</grit-part>
  10620. \ No newline at end of file
  10621. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  10622. --- a/tools/gritsettings/resource_ids.spec
  10623. +++ b/tools/gritsettings/resource_ids.spec
  10624. @@ -642,6 +642,12 @@
  10625. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  10626. "includes": [3720]
  10627. },
  10628. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  10629. + "includes": [6000],
  10630. + },
  10631. + "components/user_scripts/browser/resources/browser_resources.grd": {
  10632. + "includes": [6020],
  10633. + },
  10634. # END components/ section.
  10635. # START ios/ section.
  10636. --
  10637. 2.25.1