Experimental-user-scripts-support.patch 389 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Fri, 13 Aug 2021 17:10:47 +0000
  3. Subject: Experimental user scripts support
  4. Activate the user scripts functionality for Android,
  5. as it is available in the Desktop version.
  6. It is possible to add user scripts in two ways: by
  7. selecting files from the picker in the settings or
  8. downloading the scripts and opening them from downloads
  9. (only if such files end with '.user.js').
  10. New imported scripts are disabled by default: they
  11. can be activated via the UI.
  12. Parsed user script headers are: name, version, description,
  13. include, exclude, match, exclude_match (only http and
  14. https), run-at (document-start, document-end,
  15. document-idle), homepage, url_source
  16. The UI also allows you to see the source of the script.
  17. See also: components/user_scripts/README.md
  18. Requires patch: Adds-support-for-writing-URIs.patch
  19. ---
  20. chrome/android/BUILD.gn | 5 +
  21. .../android/java/res/xml/main_preferences.xml | 5 +
  22. .../browser/download/DownloadUtils.java | 6 +
  23. .../init/ProcessInitializationHandler.java | 3 +
  24. chrome/android/java_sources.gni | 3 +
  25. chrome/browser/BUILD.gn | 5 +
  26. chrome/browser/about_flags.cc | 5 +
  27. .../browser/chrome_content_browser_client.cc | 3 +-
  28. chrome/browser/flag_descriptions.cc | 5 +
  29. chrome/browser/flag_descriptions.h | 3 +
  30. chrome/browser/prefs/browser_prefs.cc | 2 +
  31. chrome/browser/profiles/BUILD.gn | 1 +
  32. ...hrome_browser_main_extra_parts_profiles.cc | 3 +
  33. chrome/browser/profiles/profile_manager.cc | 9 +
  34. chrome/browser/profiles/renderer_updater.cc | 10 +-
  35. chrome/browser/profiles/renderer_updater.h | 1 +
  36. .../webui/chrome_web_ui_controller_factory.cc | 3 +
  37. chrome/chrome_paks.gni | 2 +
  38. chrome/common/renderer_configuration.mojom | 1 +
  39. chrome/renderer/BUILD.gn | 1 +
  40. .../chrome_content_renderer_client.cc | 37 +
  41. .../renderer/chrome_render_thread_observer.cc | 3 +
  42. components/components_strings.grd | 1 +
  43. components/user_scripts/README.md | 150 ++++
  44. components/user_scripts/android/BUILD.gn | 80 ++
  45. .../java/res/layout/accept_script_item.xml | 160 ++++
  46. .../java/res/layout/accept_script_list.xml | 10 +
  47. .../java/res/layout/scripts_preference.xml | 40 +
  48. .../android/java/res/values/dimens.xml | 11 +
  49. .../java/res/xml/userscripts_preferences.xml | 34 +
  50. .../user_scripts/UserScriptsUtils.java | 87 ++
  51. .../user_scripts/FragmentWindowAndroid.java | 90 ++
  52. .../user_scripts/IUserScriptsUtils.java | 22 +
  53. .../components/user_scripts/ScriptInfo.java | 37 +
  54. .../user_scripts/ScriptListBaseAdapter.java | 163 ++++
  55. .../user_scripts/ScriptListPreference.java | 171 ++++
  56. .../user_scripts/UserScriptsBridge.java | 212 +++++
  57. .../user_scripts/UserScriptsPreferences.java | 116 +++
  58. .../user_scripts/android/java_sources.gni | 18 +
  59. .../android/user_scripts_bridge.cc | 173 ++++
  60. .../android/user_scripts_bridge.h | 31 +
  61. components/user_scripts/browser/BUILD.gn | 82 ++
  62. .../user_scripts/browser/file_task_runner.cc | 40 +
  63. .../user_scripts/browser/file_task_runner.h | 34 +
  64. .../browser/resources/browser_resources.grd | 14 +
  65. .../browser/resources/user-script-ui/BUILD.gn | 12 +
  66. .../user-script-ui/user-scripts-ui.html | 14 +
  67. .../user-script-ui/user-scripts-ui.js | 9 +
  68. .../browser/ui/user_scripts_ui.cc | 147 ++++
  69. .../user_scripts/browser/ui/user_scripts_ui.h | 37 +
  70. .../browser/user_script_loader.cc | 716 ++++++++++++++++
  71. .../user_scripts/browser/user_script_loader.h | 169 ++++
  72. .../browser/user_script_pref_info.cc | 34 +
  73. .../browser/user_script_pref_info.h | 72 ++
  74. .../user_scripts/browser/user_script_prefs.cc | 278 ++++++
  75. .../user_scripts/browser/user_script_prefs.h | 62 ++
  76. .../browser/userscripts_browser_client.cc | 78 ++
  77. .../browser/userscripts_browser_client.h | 62 ++
  78. components/user_scripts/common/BUILD.gn | 49 ++
  79. components/user_scripts/common/constants.h | 21 +
  80. components/user_scripts/common/error_utils.cc | 54 ++
  81. components/user_scripts/common/error_utils.h | 24 +
  82. .../common/extension_message_generator.cc | 29 +
  83. .../common/extension_message_generator.h | 11 +
  84. .../user_scripts/common/extension_messages.cc | 40 +
  85. .../user_scripts/common/extension_messages.h | 70 ++
  86. components/user_scripts/common/host_id.cc | 31 +
  87. components/user_scripts/common/host_id.h | 35 +
  88. .../user_scripts/common/script_constants.h | 33 +
  89. components/user_scripts/common/url_pattern.cc | 803 ++++++++++++++++++
  90. components/user_scripts/common/url_pattern.h | 302 +++++++
  91. .../user_scripts/common/url_pattern_set.cc | 335 ++++++++
  92. .../user_scripts/common/url_pattern_set.h | 160 ++++
  93. components/user_scripts/common/user_script.cc | 329 +++++++
  94. components/user_scripts/common/user_script.h | 403 +++++++++
  95. .../common/user_scripts_features.cc | 32 +
  96. .../common/user_scripts_features.h | 34 +
  97. components/user_scripts/common/view_type.cc | 39 +
  98. components/user_scripts/common/view_type.h | 48 ++
  99. components/user_scripts/renderer/BUILD.gn | 67 ++
  100. .../renderer/extension_frame_helper.cc | 96 +++
  101. .../renderer/extension_frame_helper.h | 91 ++
  102. .../user_scripts/renderer/injection_host.cc | 12 +
  103. .../user_scripts/renderer/injection_host.h | 41 +
  104. .../renderer/resources/greasemonkey_api.js | 82 ++
  105. .../user_scripts_renderer_resources.grd | 14 +
  106. .../user_scripts/renderer/script_context.cc | 215 +++++
  107. .../user_scripts/renderer/script_context.h | 69 ++
  108. .../user_scripts/renderer/script_injection.cc | 343 ++++++++
  109. .../user_scripts/renderer/script_injection.h | 154 ++++
  110. .../renderer/script_injection_callback.cc | 25 +
  111. .../renderer/script_injection_callback.h | 38 +
  112. .../renderer/script_injection_manager.cc | 417 +++++++++
  113. .../renderer/script_injection_manager.h | 101 +++
  114. .../user_scripts/renderer/script_injector.h | 96 +++
  115. .../user_scripts/renderer/scripts_run_info.cc | 31 +
  116. .../user_scripts/renderer/scripts_run_info.h | 69 ++
  117. .../renderer/user_script_injector.cc | 228 +++++
  118. .../renderer/user_script_injector.h | 86 ++
  119. .../user_scripts/renderer/user_script_set.cc | 262 ++++++
  120. .../user_scripts/renderer/user_script_set.h | 101 +++
  121. .../renderer/user_script_set_manager.cc | 77 ++
  122. .../renderer/user_script_set_manager.h | 61 ++
  123. .../renderer/user_scripts_dispatcher.cc | 36 +
  124. .../renderer/user_scripts_dispatcher.h | 49 ++
  125. .../renderer/user_scripts_renderer_client.cc | 105 +++
  126. .../renderer/user_scripts_renderer_client.h | 37 +
  127. .../renderer/web_ui_injection_host.cc | 40 +
  128. .../renderer/web_ui_injection_host.h | 27 +
  129. .../strings/userscripts_strings.grdp | 57 ++
  130. tools/gritsettings/resource_ids.spec | 6 +
  131. 111 files changed, 9595 insertions(+), 2 deletions(-)
  132. create mode 100644 components/user_scripts/README.md
  133. create mode 100755 components/user_scripts/android/BUILD.gn
  134. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_item.xml
  135. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_list.xml
  136. create mode 100644 components/user_scripts/android/java/res/layout/scripts_preference.xml
  137. create mode 100755 components/user_scripts/android/java/res/values/dimens.xml
  138. create mode 100644 components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  139. create mode 100755 components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  140. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  141. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  142. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  143. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  144. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  145. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  146. create mode 100755 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  147. create mode 100644 components/user_scripts/android/java_sources.gni
  148. create mode 100644 components/user_scripts/android/user_scripts_bridge.cc
  149. create mode 100644 components/user_scripts/android/user_scripts_bridge.h
  150. create mode 100755 components/user_scripts/browser/BUILD.gn
  151. create mode 100755 components/user_scripts/browser/file_task_runner.cc
  152. create mode 100755 components/user_scripts/browser/file_task_runner.h
  153. create mode 100644 components/user_scripts/browser/resources/browser_resources.grd
  154. create mode 100644 components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  155. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  156. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  157. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.cc
  158. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.h
  159. create mode 100755 components/user_scripts/browser/user_script_loader.cc
  160. create mode 100755 components/user_scripts/browser/user_script_loader.h
  161. create mode 100644 components/user_scripts/browser/user_script_pref_info.cc
  162. create mode 100644 components/user_scripts/browser/user_script_pref_info.h
  163. create mode 100644 components/user_scripts/browser/user_script_prefs.cc
  164. create mode 100644 components/user_scripts/browser/user_script_prefs.h
  165. create mode 100755 components/user_scripts/browser/userscripts_browser_client.cc
  166. create mode 100755 components/user_scripts/browser/userscripts_browser_client.h
  167. create mode 100755 components/user_scripts/common/BUILD.gn
  168. create mode 100755 components/user_scripts/common/constants.h
  169. create mode 100755 components/user_scripts/common/error_utils.cc
  170. create mode 100755 components/user_scripts/common/error_utils.h
  171. create mode 100755 components/user_scripts/common/extension_message_generator.cc
  172. create mode 100755 components/user_scripts/common/extension_message_generator.h
  173. create mode 100755 components/user_scripts/common/extension_messages.cc
  174. create mode 100755 components/user_scripts/common/extension_messages.h
  175. create mode 100755 components/user_scripts/common/host_id.cc
  176. create mode 100755 components/user_scripts/common/host_id.h
  177. create mode 100755 components/user_scripts/common/script_constants.h
  178. create mode 100755 components/user_scripts/common/url_pattern.cc
  179. create mode 100755 components/user_scripts/common/url_pattern.h
  180. create mode 100755 components/user_scripts/common/url_pattern_set.cc
  181. create mode 100755 components/user_scripts/common/url_pattern_set.h
  182. create mode 100755 components/user_scripts/common/user_script.cc
  183. create mode 100755 components/user_scripts/common/user_script.h
  184. create mode 100644 components/user_scripts/common/user_scripts_features.cc
  185. create mode 100644 components/user_scripts/common/user_scripts_features.h
  186. create mode 100755 components/user_scripts/common/view_type.cc
  187. create mode 100755 components/user_scripts/common/view_type.h
  188. create mode 100755 components/user_scripts/renderer/BUILD.gn
  189. create mode 100755 components/user_scripts/renderer/extension_frame_helper.cc
  190. create mode 100755 components/user_scripts/renderer/extension_frame_helper.h
  191. create mode 100755 components/user_scripts/renderer/injection_host.cc
  192. create mode 100755 components/user_scripts/renderer/injection_host.h
  193. create mode 100755 components/user_scripts/renderer/resources/greasemonkey_api.js
  194. create mode 100755 components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  195. create mode 100755 components/user_scripts/renderer/script_context.cc
  196. create mode 100755 components/user_scripts/renderer/script_context.h
  197. create mode 100755 components/user_scripts/renderer/script_injection.cc
  198. create mode 100755 components/user_scripts/renderer/script_injection.h
  199. create mode 100755 components/user_scripts/renderer/script_injection_callback.cc
  200. create mode 100755 components/user_scripts/renderer/script_injection_callback.h
  201. create mode 100755 components/user_scripts/renderer/script_injection_manager.cc
  202. create mode 100755 components/user_scripts/renderer/script_injection_manager.h
  203. create mode 100755 components/user_scripts/renderer/script_injector.h
  204. create mode 100755 components/user_scripts/renderer/scripts_run_info.cc
  205. create mode 100755 components/user_scripts/renderer/scripts_run_info.h
  206. create mode 100755 components/user_scripts/renderer/user_script_injector.cc
  207. create mode 100755 components/user_scripts/renderer/user_script_injector.h
  208. create mode 100755 components/user_scripts/renderer/user_script_set.cc
  209. create mode 100755 components/user_scripts/renderer/user_script_set.h
  210. create mode 100755 components/user_scripts/renderer/user_script_set_manager.cc
  211. create mode 100755 components/user_scripts/renderer/user_script_set_manager.h
  212. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.cc
  213. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.h
  214. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.cc
  215. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.h
  216. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.cc
  217. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.h
  218. create mode 100755 components/user_scripts/strings/userscripts_strings.grdp
  219. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  220. --- a/chrome/android/BUILD.gn
  221. +++ b/chrome/android/BUILD.gn
  222. @@ -269,6 +269,10 @@ android_resources("chrome_app_java_resources") {
  223. "//third_party/androidx:androidx_gridlayout_gridlayout_java",
  224. "//third_party/androidx:androidx_preference_preference_java",
  225. ]
  226. +
  227. + # this need to be into android_resources("chrome_app_java_resources") section because
  228. + # android:java_resources are packed *_percent.pak and placed in the executable folder
  229. + deps += [ "//components/user_scripts/android:java_resources" ]
  230. }
  231. if (enable_vr) {
  232. @@ -561,6 +565,7 @@ android_library("chrome_java") {
  233. "//components/ukm/android:java",
  234. "//components/url_formatter/android:url_formatter_java",
  235. "//components/user_prefs/android:java",
  236. + "//components/user_scripts/android:java",
  237. "//components/variations/android:variations_java",
  238. "//components/version_info/android:version_constants_java",
  239. "//components/viz/common:common_java",
  240. diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
  241. --- a/chrome/android/java/res/xml/main_preferences.xml
  242. +++ b/chrome/android/java/res/xml/main_preferences.xml
  243. @@ -86,6 +86,11 @@
  244. android:key="useragent_settings"
  245. android:order="20"
  246. android:title="@string/prefs_useragent_settings"/>
  247. + <Preference
  248. + android:fragment="org.chromium.components.user_scripts.UserScriptsPreferences"
  249. + android:key="userscripts_settings"
  250. + android:order="20"
  251. + android:title="@string/prefs_userscripts_settings"/>
  252. <Preference
  253. android:fragment="org.chromium.chrome.browser.language.settings.LanguageSettings"
  254. android:key="languages"
  255. 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
  256. --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  257. +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  258. @@ -70,6 +70,7 @@ import org.chromium.content_public.browser.BrowserStartupController;
  259. import org.chromium.content_public.browser.LoadUrlParams;
  260. import org.chromium.ui.base.DeviceFormFactor;
  261. import org.chromium.ui.widget.Toast;
  262. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  263. import java.io.File;
  264. @@ -417,6 +418,11 @@ public class DownloadUtils {
  265. public static boolean openFile(String filePath, String mimeType, String downloadGuid,
  266. OTRProfileID otrProfileID, String originalUrl, String referrer,
  267. @DownloadOpenSource int source, Context context) {
  268. + if (UserScriptsUtils.getInstance().openFile(filePath, mimeType, downloadGuid,
  269. + originalUrl, referrer,
  270. + getUriForItem(filePath))) {
  271. + return true;
  272. + }
  273. DownloadMetrics.recordDownloadOpen(source, mimeType);
  274. DownloadManagerService service = DownloadManagerService.getDownloadManagerService();
  275. 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
  276. --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  277. +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
  278. @@ -122,6 +122,8 @@ import java.util.Date;
  279. import java.util.List;
  280. import java.util.Locale;
  281. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  282. +
  283. /**
  284. * Handles the initialization dependences of the browser process. This is meant to handle the
  285. * initialization that is not tied to any particular Activity, and the logic that should only be
  286. @@ -322,6 +324,7 @@ public class ProcessInitializationHandler {
  287. DefaultBrowserInfo.initBrowserFetcher();
  288. + UserScriptsUtils.Initialize();
  289. AfterStartupTaskUtils.setStartupComplete();
  290. PartnerBrowserCustomizations.getInstance().setOnInitializeAsyncFinished(
  291. diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
  292. --- a/chrome/android/java_sources.gni
  293. +++ b/chrome/android/java_sources.gni
  294. @@ -24,6 +24,7 @@ import("//components/feed/features.gni")
  295. import("//components/offline_pages/buildflags/features.gni")
  296. import("//components/omnibox/browser/test_java_sources.gni")
  297. import("//device/vr/buildflags/buildflags.gni")
  298. +import("//components/user_scripts/android/java_sources.gni")
  299. chrome_java_sources += public_autofill_assistant_java_sources
  300. @@ -62,3 +63,5 @@ if (enable_arcore) {
  301. "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java",
  302. ]
  303. }
  304. +
  305. +chrome_java_sources += userscripts_java_sources
  306. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  307. --- a/chrome/browser/BUILD.gn
  308. +++ b/chrome/browser/BUILD.gn
  309. @@ -3515,6 +3515,11 @@ static_library("browser") {
  310. ]
  311. deps += [ "//chrome/android/modules/dev_ui/provider:native" ]
  312. }
  313. + deps += [
  314. + "//components/user_scripts/common",
  315. + "//components/user_scripts/browser",
  316. + "//components/user_scripts/android",
  317. + ]
  318. } else {
  319. #!is_android
  320. if (!is_chromeos_lacros) {
  321. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
  322. --- a/chrome/browser/about_flags.cc
  323. +++ b/chrome/browser/about_flags.cc
  324. @@ -147,6 +147,7 @@
  325. #include "components/translate/core/browser/translate_ranker_impl.h"
  326. #include "components/translate/core/common/translate_util.h"
  327. #include "components/ui_devtools/switches.h"
  328. +#include "components/user_scripts/common/user_scripts_features.h"
  329. #include "components/version_info/version_info.h"
  330. #include "components/viz/common/features.h"
  331. #include "components/viz/common/switches.h"
  332. @@ -6932,6 +6933,10 @@ const FeatureEntry kFeatureEntries[] = {
  333. chromeos::features::kClipboardHistoryNudgeSessionReset)},
  334. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  335. + {"enable-userscripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  336. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  337. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  338. +
  339. #if BUILDFLAG(IS_WIN)
  340. {"enable-media-foundation-video-capture",
  341. flag_descriptions::kEnableMediaFoundationVideoCaptureName,
  342. diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
  343. --- a/chrome/browser/chrome_content_browser_client.cc
  344. +++ b/chrome/browser/chrome_content_browser_client.cc
  345. @@ -4708,7 +4708,8 @@ ChromeContentBrowserClient::CreateURLLoaderThrottles(
  346. chrome::mojom::DynamicParams dynamic_params = {
  347. profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch),
  348. profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict),
  349. - profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)};
  350. + profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps),
  351. + false /*-> allow_userscript, don't care */};
  352. result.push_back(std::make_unique<GoogleURLLoaderThrottle>(
  353. #if BUILDFLAG(IS_ANDROID)
  354. client_data_header, is_tab_large_enough,
  355. diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
  356. --- a/chrome/browser/flag_descriptions.cc
  357. +++ b/chrome/browser/flag_descriptions.cc
  358. @@ -5739,6 +5739,11 @@ const char kQuickCommandsDescription[] =
  359. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
  360. // BUILDFLAG(IS_FUCHSIA)
  361. +const char kEnableLoggingUserScriptsName[] = "Enable logging user scripts component";
  362. +const char kEnableLoggingUserScriptsDescription[] =
  363. + "Enables logging for troubleshooting feature. "
  364. + "Enabling logs may make browsing slower.";
  365. +
  366. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  367. const char kWebShareName[] = "Web Share";
  368. const char kWebShareDescription[] =
  369. diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
  370. --- a/chrome/browser/flag_descriptions.h
  371. +++ b/chrome/browser/flag_descriptions.h
  372. @@ -3310,6 +3310,9 @@ extern const char kQuickCommandsDescription[];
  373. #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
  374. // defined (OS_FUCHSIA)
  375. +extern const char kEnableLoggingUserScriptsName[];
  376. +extern const char kEnableLoggingUserScriptsDescription[];
  377. +
  378. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  379. extern const char kWebShareName[];
  380. extern const char kWebShareDescription[];
  381. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  382. --- a/chrome/browser/prefs/browser_prefs.cc
  383. +++ b/chrome/browser/prefs/browser_prefs.cc
  384. @@ -241,6 +241,7 @@
  385. #include "components/ntp_tiles/popular_sites_impl.h"
  386. #include "components/permissions/contexts/geolocation_permission_context_android.h"
  387. #include "components/query_tiles/tile_service_prefs.h"
  388. +#include "components/user_scripts/browser/user_script_prefs.h"
  389. #else // BUILDFLAG(IS_ANDROID)
  390. #include "chrome/browser/cart/cart_service.h"
  391. #include "chrome/browser/device_api/device_service_impl.h"
  392. @@ -1304,6 +1305,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
  393. translate::TranslatePrefs::RegisterProfilePrefs(registry);
  394. omnibox::RegisterProfilePrefs(registry);
  395. ZeroSuggestProvider::RegisterProfilePrefs(registry);
  396. + user_scripts::UserScriptsPrefs::RegisterProfilePrefs(registry);
  397. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  398. RegisterSessionServiceLogProfilePrefs(registry);
  399. diff --git a/chrome/browser/profiles/BUILD.gn b/chrome/browser/profiles/BUILD.gn
  400. --- a/chrome/browser/profiles/BUILD.gn
  401. +++ b/chrome/browser/profiles/BUILD.gn
  402. @@ -45,6 +45,7 @@ source_set("profile") {
  403. "//components/profile_metrics",
  404. "//components/sync/driver",
  405. "//components/variations",
  406. + "//components/user_scripts/browser",
  407. "//content/public/browser",
  408. "//extensions/buildflags",
  409. ]
  410. diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  411. --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  412. +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  413. @@ -238,6 +238,8 @@
  414. #include "chrome/browser/ui/cocoa/screentime/screentime_features.h"
  415. #endif
  416. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  417. +
  418. namespace chrome {
  419. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  420. @@ -567,6 +569,7 @@ void ChromeBrowserMainExtraPartsProfiles::
  421. #endif
  422. WebDataServiceFactory::GetInstance();
  423. webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
  424. + user_scripts::UserScriptsBrowserClient::GetInstance();
  425. }
  426. void ChromeBrowserMainExtraPartsProfiles::PreProfileInit() {
  427. diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
  428. --- a/chrome/browser/profiles/profile_manager.cc
  429. +++ b/chrome/browser/profiles/profile_manager.cc
  430. @@ -115,6 +115,8 @@
  431. #include "extensions/common/manifest.h"
  432. #endif
  433. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  434. +
  435. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  436. #include "chrome/browser/sessions/app_session_service_factory.h"
  437. #include "chrome/browser/sessions/session_service_factory.h"
  438. @@ -1664,6 +1666,13 @@ void ProfileManager::DoFinalInitForServices(Profile* profile,
  439. }
  440. #endif
  441. +
  442. + user_scripts::UserScriptsBrowserClient* userscript_client =
  443. + user_scripts::UserScriptsBrowserClient::GetInstance();
  444. + if (userscript_client) {
  445. + userscript_client->SetProfile(profile);
  446. + }
  447. +
  448. #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  449. // Initialization needs to happen after extension system initialization (for
  450. // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the
  451. diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
  452. --- a/chrome/browser/profiles/renderer_updater.cc
  453. +++ b/chrome/browser/profiles/renderer_updater.cc
  454. @@ -31,6 +31,8 @@
  455. #include "chrome/browser/ash/login/signin/oauth2_login_manager_factory.h"
  456. #endif
  457. +#include "components/user_scripts/browser/user_script_prefs.h"
  458. +
  459. RendererUpdater::RendererUpdater(Profile* profile)
  460. : profile_(profile),
  461. is_off_the_record_(profile_->IsOffTheRecord()),
  462. @@ -51,6 +53,7 @@ RendererUpdater::RendererUpdater(Profile* profile)
  463. force_google_safesearch_.Init(prefs::kForceGoogleSafeSearch, pref_service);
  464. force_youtube_restrict_.Init(prefs::kForceYouTubeRestrict, pref_service);
  465. allowed_domains_for_apps_.Init(prefs::kAllowedDomainsForApps, pref_service);
  466. + activate_userscripts_.Init(user_scripts::prefs::kUserScriptsEnabled, pref_service);
  467. pref_change_registrar_.Init(pref_service);
  468. pref_change_registrar_.Add(
  469. @@ -65,6 +68,10 @@ RendererUpdater::RendererUpdater(Profile* profile)
  470. prefs::kAllowedDomainsForApps,
  471. base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  472. base::Unretained(this)));
  473. + pref_change_registrar_.Add(
  474. + user_scripts::prefs::kUserScriptsEnabled,
  475. + base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  476. + base::Unretained(this)));
  477. }
  478. RendererUpdater::~RendererUpdater() {
  479. @@ -188,5 +195,6 @@ chrome::mojom::DynamicParamsPtr RendererUpdater::CreateRendererDynamicParams()
  480. const {
  481. return chrome::mojom::DynamicParams::New(
  482. force_google_safesearch_.GetValue(), force_youtube_restrict_.GetValue(),
  483. - allowed_domains_for_apps_.GetValue());
  484. + allowed_domains_for_apps_.GetValue(),
  485. + activate_userscripts_.GetValue());
  486. }
  487. diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
  488. --- a/chrome/browser/profiles/renderer_updater.h
  489. +++ b/chrome/browser/profiles/renderer_updater.h
  490. @@ -93,6 +93,7 @@ class RendererUpdater : public KeyedService,
  491. // Prefs that we sync to the renderers.
  492. BooleanPrefMember force_google_safesearch_;
  493. + BooleanPrefMember activate_userscripts_;
  494. IntegerPrefMember force_youtube_restrict_;
  495. StringPrefMember allowed_domains_for_apps_;
  496. };
  497. diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  498. --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  499. +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  500. @@ -93,6 +93,7 @@
  501. #include "components/security_interstitials/content/urls.h"
  502. #include "components/signin/public/base/signin_buildflags.h"
  503. #include "components/site_engagement/content/site_engagement_service.h"
  504. +#include "components/user_scripts/browser/ui/user_scripts_ui.h"
  505. #include "content/public/browser/web_contents.h"
  506. #include "content/public/browser/web_ui.h"
  507. #include "content/public/common/content_client.h"
  508. @@ -816,6 +817,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
  509. return &NewWebUI<UserActionsUI>;
  510. if (url.host_piece() == chrome::kChromeUIVersionHost)
  511. return &NewWebUI<VersionUI>;
  512. + if (url.host_piece() == user_scripts::kChromeUIUserScriptsHost)
  513. + return &NewWebUI<user_scripts::UserScriptsUI>;
  514. #if !BUILDFLAG(IS_ANDROID)
  515. #if !BUILDFLAG(IS_CHROMEOS)
  516. diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
  517. --- a/chrome/chrome_paks.gni
  518. +++ b/chrome/chrome_paks.gni
  519. @@ -110,6 +110,7 @@ template("chrome_extra_paks") {
  520. "$root_gen_dir/skia/skia_resources.pak",
  521. "$root_gen_dir/third_party/blink/public/resources/blink_resources.pak",
  522. "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak",
  523. + "$root_gen_dir/chrome/userscripts_browser_resources.pak",
  524. "$root_gen_dir/ui/resources/webui_generated_resources.pak",
  525. ]
  526. deps = [
  527. @@ -130,6 +131,7 @@ template("chrome_extra_paks") {
  528. "//third_party/blink/public:devtools_inspector_resources",
  529. "//third_party/blink/public:resources",
  530. "//ui/resources",
  531. + "//components/user_scripts/browser:userscripts_browser_resources_grit",
  532. ]
  533. if (defined(invoker.deps)) {
  534. deps += invoker.deps
  535. diff --git a/chrome/common/renderer_configuration.mojom b/chrome/common/renderer_configuration.mojom
  536. --- a/chrome/common/renderer_configuration.mojom
  537. +++ b/chrome/common/renderer_configuration.mojom
  538. @@ -12,6 +12,7 @@ struct DynamicParams {
  539. bool force_safe_search = true;
  540. int32 youtube_restrict = 0;
  541. string allowed_domains_for_apps;
  542. + bool allow_userscript = false;
  543. };
  544. interface ChromeOSListener {
  545. diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
  546. --- a/chrome/renderer/BUILD.gn
  547. +++ b/chrome/renderer/BUILD.gn
  548. @@ -141,6 +141,7 @@ static_library("renderer") {
  549. "//components/feed:feature_list",
  550. "//components/feed/content/renderer:feed_renderer",
  551. "//components/history_clusters/core",
  552. + "//components/user_scripts/renderer",
  553. "//components/network_hints/renderer",
  554. "//components/no_state_prefetch/common",
  555. "//components/no_state_prefetch/renderer",
  556. diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
  557. --- a/chrome/renderer/chrome_content_renderer_client.cc
  558. +++ b/chrome/renderer/chrome_content_renderer_client.cc
  559. @@ -242,6 +242,9 @@
  560. #include "chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h"
  561. #endif
  562. +#include "components/user_scripts/common/user_scripts_features.h"
  563. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  564. +
  565. using autofill::AutofillAgent;
  566. using autofill::PasswordAutofillAgent;
  567. using autofill::PasswordGenerationAgent;
  568. @@ -414,6 +417,12 @@ void ChromeContentRendererClient::RenderThreadStarted() {
  569. WebString::FromASCII(extensions::kExtensionScheme));
  570. #endif
  571. + user_scripts::UserScriptsRendererClient* userscript_client =
  572. + user_scripts::UserScriptsRendererClient::GetInstance();
  573. + if (userscript_client) {
  574. + userscript_client->RenderThreadStarted();
  575. + }
  576. +
  577. #if BUILDFLAG(ENABLE_SPELLCHECK)
  578. if (!spellcheck_)
  579. InitSpellCheck();
  580. @@ -543,6 +552,13 @@ void ChromeContentRendererClient::RenderFrameCreated(
  581. render_frame, registry);
  582. #endif
  583. + user_scripts::UserScriptsRendererClient* userscript_client =
  584. + user_scripts::UserScriptsRendererClient::GetInstance();
  585. + if (userscript_client) {
  586. + userscript_client->RenderFrameCreated(
  587. + render_frame, registry);
  588. + }
  589. +
  590. #if BUILDFLAG(ENABLE_PLUGINS)
  591. new PepperHelper(render_frame);
  592. #endif
  593. @@ -1531,7 +1547,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentStart(
  594. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentStart(
  595. render_frame);
  596. // |render_frame| might be dead by now.
  597. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  598. #endif
  599. + user_scripts::UserScriptsRendererClient* userscript_client =
  600. + user_scripts::UserScriptsRendererClient::GetInstance();
  601. + if (userscript_client) {
  602. + userscript_client->RunScriptsAtDocumentStart(
  603. + render_frame);
  604. + }
  605. }
  606. void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  607. @@ -1540,7 +1563,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  608. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentEnd(
  609. render_frame);
  610. // |render_frame| might be dead by now.
  611. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  612. #endif
  613. + user_scripts::UserScriptsRendererClient* userscript_client =
  614. + user_scripts::UserScriptsRendererClient::GetInstance();
  615. + if (userscript_client) {
  616. + userscript_client->RunScriptsAtDocumentEnd(
  617. + render_frame);
  618. + }
  619. }
  620. void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  621. @@ -1549,7 +1579,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  622. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentIdle(
  623. render_frame);
  624. // |render_frame| might be dead by now.
  625. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  626. #endif
  627. + user_scripts::UserScriptsRendererClient* userscript_client =
  628. + user_scripts::UserScriptsRendererClient::GetInstance();
  629. + if (userscript_client) {
  630. + userscript_client->RunScriptsAtDocumentIdle(
  631. + render_frame);
  632. + }
  633. }
  634. void ChromeContentRendererClient::
  635. diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc
  636. --- a/chrome/renderer/chrome_render_thread_observer.cc
  637. +++ b/chrome/renderer/chrome_render_thread_observer.cc
  638. @@ -57,6 +57,8 @@
  639. #include "third_party/blink/public/web/web_security_policy.h"
  640. #include "third_party/blink/public/web/web_view.h"
  641. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  642. +
  643. #if BUILDFLAG(ENABLE_EXTENSIONS)
  644. #include "extensions/renderer/localization_peer.h"
  645. #endif
  646. @@ -254,6 +256,7 @@ void ChromeRenderThreadObserver::SetInitialConfiguration(
  647. void ChromeRenderThreadObserver::SetConfiguration(
  648. chrome::mojom::DynamicParamsPtr params) {
  649. *GetDynamicConfigParams() = std::move(*params);
  650. + user_scripts::UserScriptsRendererClient::GetInstance()->ConfigurationUpdated();
  651. }
  652. void ChromeRenderThreadObserver::OnRendererConfigurationAssociatedRequest(
  653. diff --git a/components/components_strings.grd b/components/components_strings.grd
  654. --- a/components/components_strings.grd
  655. +++ b/components/components_strings.grd
  656. @@ -335,6 +335,7 @@
  657. <part file="undo_strings.grdp" />
  658. <part file="version_ui_strings.grdp" />
  659. <part file="webapps_strings.grdp" />
  660. + <part file="user_scripts/strings/userscripts_strings.grdp" />
  661. <if expr="not is_ios">
  662. <part file="management_strings.grdp" />
  663. diff --git a/components/user_scripts/README.md b/components/user_scripts/README.md
  664. new file mode 100644
  665. --- /dev/null
  666. +++ b/components/user_scripts/README.md
  667. @@ -0,0 +1,150 @@
  668. +# Userscripts support for Bromite
  669. +
  670. +UserScript support is under user setting currently disabled by default: when disabled, no code that can impact navigation safety is active.
  671. +
  672. +Activation allows the use of userscripts in Bromite. It is possible to add them in two ways:
  673. +- by selecting files from the file picker in the settings
  674. +- downloading the scripts and opening it from downloads (only if ends with .user.js)
  675. +The new imported scripts are disabled by default: they can be activated via the menu visible on the ui.
  676. +
  677. +Userscript support is currently the one provided by the desktop version. The enabled headers are:
  678. +
  679. +- `@name`
  680. +- `@version`
  681. +- `@description`
  682. +- `@url` or `@homepage`
  683. +- `@include`, `@exclude`, `@match`, `@exclude_match` for the url pattern (only http e https)
  684. +- `@run-at`
  685. + - `document-start`
  686. + Start the script after the documentElement is created, but before anything else happens
  687. + - `document-end`
  688. + Start the script after the entire document is parsed. Same as DOMContentLoaded
  689. + - `document-idle`
  690. + 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
  691. +
  692. +The url-patterns are so defined:
  693. +```
  694. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  695. +// <scheme> := '*' | 'http' | 'https'
  696. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  697. +// '*.' <anychar except '/' and '*'>+
  698. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  699. +// <path> := '/' <any chars>
  700. +//
  701. +// * Host is not used when the scheme is 'file'.
  702. +// * The path can have embedded '*' characters which act as glob wildcards.
  703. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  704. +// a valid scheme (as specified by valid_schemes_).
  705. +// * The '*' scheme pattern excludes file URLs.
  706. +//
  707. +// Examples of valid patterns:
  708. +// - http://*/*
  709. +// - http://*/foo*
  710. +// - https://*.google.com/foo*bar
  711. +// - file://monkey*
  712. +// - http://127.0.0.1/*
  713. +// - http://[2607:f8b0:4005:805::200e]/*
  714. +//
  715. +// Examples of invalid patterns:
  716. +// - http://* -- path not specified
  717. +// - http://*foo/bar -- * not allowed as substring of host component
  718. +// - http://foo.*.bar/baz -- * must be first component
  719. +// - http:/bar -- scheme separator not found
  720. +// - foo://* -- invalid scheme
  721. +// - chrome:// -- we don't support chrome internal URLs
  722. +```
  723. +
  724. +---
  725. +## **Beware of the scripts you enter: they can be a source of security problems, you are injecting code into your navigation**.
  726. +---
  727. +## Technical aspects
  728. +
  729. +`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.
  730. +
  731. +In `user_scripts/browser` you find the actual management (in the browser process) and in `android` basically the settings ui.
  732. +
  733. +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.
  734. +
  735. +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.
  736. +
  737. +There is also support for an on-line help at https://github.com/bromite/bromite/wiki/UserScripts.
  738. +
  739. +
  740. +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.
  741. +
  742. +for userscripts_browser_client.cc
  743. +- `chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc`
  744. +builds the browser side. also gpu process passes here, but the call is avoided.
  745. +
  746. +- `chrome/browser/profiles/profile_manager.cc`
  747. +set the profile
  748. +
  749. +for renderer/user_scripts_renderer_client.cc
  750. +- `chrome/renderer/chrome_content_renderer_client.cc`
  751. +at the renderer side
  752. +
  753. +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`).
  754. +
  755. +## BROWSER PROCESS
  756. +Once the profile is set, it istance the `components/user_scripts/browser/user_script_loader.cc` and starts it.
  757. +This loads all the files in the folder into the runner file and interprets them. Control then passes to
  758. +`components/user_scripts/browser/user_script_prefs.cc` which verifies through the default profile what the user wants active.
  759. +At that point it passes through IPC to the renderer only the list of active scripts.
  760. +
  761. +## RENDERER PROCESS
  762. +Each time a frame is created, the script pattern is checked and it is injected into the three stages (START, IDLE, END).
  763. +The logic is all in `components/user_scripts/renderer/user_script_set.cc`.
  764. +
  765. +## Simple example
  766. +Here you find a working example that eliminates the google popup, useful in always incognito:
  767. +```
  768. +// ==UserScript==
  769. +// @name Remove Google Consent
  770. +// @namespace google
  771. +// @version 0.0.1
  772. +// @description Autohide Accepts Cookies
  773. +// @author uazo
  774. +// @match https://*.google.com/search?*
  775. +// @grant none
  776. +// @run-at document-start
  777. +// ==/UserScript==
  778. +
  779. +(function() {
  780. + 'use strict';
  781. +
  782. + var prepareStyleSheet = function() {
  783. + var style = document.createElement('style');
  784. + //style.setAttribute('media', 'screen');
  785. + style.appendChild(document.createTextNode(''));
  786. + document.head.appendChild(style);
  787. + style.sheet.insertRule('body { overflow:scroll !important;position:unset !important }');
  788. + };
  789. +
  790. + var hideConsent = function() {
  791. + document.getElementById("lb").style.display = "none";
  792. + };
  793. +
  794. + var checkElementThenRun = function(selector, func) {
  795. + var el = document.querySelector(selector);
  796. + if ( el == null ) {
  797. + if (window.requestAnimationFrame != undefined) {
  798. + window.requestAnimationFrame(function(){ checkElementThenRun(selector, func)});
  799. + } else {
  800. + document.addEventListener('readystatechange', function(e) {
  801. + if (document.readyState == 'complete') {
  802. + func();
  803. + }
  804. + });
  805. + }
  806. + } else {
  807. + func();
  808. + }
  809. + }
  810. +
  811. + document.cookie = 'CONSENT=YES+IT.it+V13+BX;domain=.google.com';
  812. + checkElementThenRun('head', prepareStyleSheet);
  813. + checkElementThenRun('#lb', hideConsent);
  814. +})();
  815. +```
  816. +
  817. +See also: https://github.com/bromite/bromite/pull/857
  818. diff --git a/components/user_scripts/android/BUILD.gn b/components/user_scripts/android/BUILD.gn
  819. new file mode 100755
  820. --- /dev/null
  821. +++ b/components/user_scripts/android/BUILD.gn
  822. @@ -0,0 +1,80 @@
  823. +# This file is part of Bromite.
  824. +
  825. +# Bromite is free software: you can redistribute it and/or modify
  826. +# it under the terms of the GNU General Public License as published by
  827. +# the Free Software Foundation, either version 3 of the License, or
  828. +# (at your option) any later version.
  829. +
  830. +# Bromite is distributed in the hope that it will be useful,
  831. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  832. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  833. +# GNU General Public License for more details.
  834. +
  835. +# You should have received a copy of the GNU General Public License
  836. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  837. +
  838. +import("//build/config/android/rules.gni")
  839. +
  840. +generate_jni("user_scripts_jni_headers") {
  841. + sources = [ "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java" ]
  842. +}
  843. +
  844. +android_resources("java_resources") {
  845. + sources = [
  846. + "java/res/xml/userscripts_preferences.xml",
  847. + "java/res/layout/accept_script_item.xml",
  848. + "java/res/layout/accept_script_list.xml",
  849. + "java/res/layout/scripts_preference.xml",
  850. + "java/res/values/dimens.xml"
  851. + ]
  852. +
  853. + deps = [
  854. + "//components/browser_ui/strings/android:browser_ui_strings_grd",
  855. + "//components/browser_ui/styles/android:java_resources",
  856. + "//components/strings:components_strings_grd",
  857. + "//ui/android:ui_java_resources",
  858. + ]
  859. +}
  860. +
  861. +android_library("java") {
  862. + sources = [
  863. + "java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java",
  864. + "java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java",
  865. + "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java",
  866. + "java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java",
  867. + "java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java",
  868. + "java/src/org/chromium/components/user_scripts/ScriptListPreference.java",
  869. + "java/src/org/chromium/components/user_scripts/ScriptInfo.java",
  870. + ]
  871. + deps = [
  872. + ":java_resources",
  873. + "//base:base_java",
  874. + "//base:jni_java",
  875. + "//components/embedder_support/android:browser_context_java",
  876. + "//components/browser_ui/settings/android:java",
  877. + "//components/browser_ui/widget/android:java",
  878. + "//content/public/android:content_java",
  879. + "//components/prefs/android:java",
  880. + "//third_party/android_deps:android_support_v7_appcompat_java",
  881. + "//third_party/androidx:androidx_annotation_annotation_java",
  882. + "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
  883. + "//third_party/androidx:androidx_preference_preference_java",
  884. + "//ui/android:ui_java",
  885. + ]
  886. + resources_package = "org.chromium.components.user_scripts"
  887. + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
  888. +}
  889. +
  890. +source_set("android") {
  891. + sources = [
  892. + "user_scripts_bridge.cc",
  893. + "user_scripts_bridge.h",
  894. + ]
  895. + deps = [
  896. + ":user_scripts_jni_headers",
  897. + "//base",
  898. + "//components/user_scripts/browser",
  899. + "//components/permissions",
  900. + "//content/public/browser",
  901. + ]
  902. +}
  903. 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
  904. new file mode 100644
  905. --- /dev/null
  906. +++ b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  907. @@ -0,0 +1,160 @@
  908. +<?xml version="1.0" encoding="utf-8"?>
  909. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  910. + Use of this source code is governed by a BSD-style license that can be
  911. + found in the LICENSE file. -->
  912. +
  913. +<LinearLayout
  914. + xmlns:android="http://schemas.android.com/apk/res/android"
  915. + xmlns:app="http://schemas.android.com/apk/res-auto"
  916. + xmlns:tools="http://schemas.android.com/tools"
  917. + android:layout_width="match_parent"
  918. + android:layout_height="wrap_content"
  919. + android:orientation="vertical"
  920. + android:layout_gravity="center_vertical" >
  921. +
  922. + <LinearLayout
  923. + android:layout_marginStart="0dp"
  924. + android:paddingStart="@dimen/draggable_list_item_padding"
  925. + android:paddingEnd="@dimen/draggable_list_item_padding"
  926. + style="@style/ListItemContainer">
  927. +
  928. + <Switch
  929. + android:id="@+id/switch_widget"
  930. + android:layout_width="wrap_content"
  931. + android:layout_height="wrap_content"
  932. + android:paddingEnd="15dp"
  933. + android:focusable="false"
  934. + android:background="@null" />
  935. +
  936. + <LinearLayout
  937. + android:layout_width="0dp"
  938. + android:layout_height="wrap_content"
  939. + android:layout_weight="1"
  940. + android:orientation="vertical"
  941. + android:layout_gravity="center_vertical" >
  942. +
  943. + <TextView
  944. + android:id="@+id/title"
  945. + android:layout_width="match_parent"
  946. + android:layout_height="wrap_content"
  947. + style="@style/PreferenceTitle" />
  948. +
  949. + <TextView
  950. + android:id="@+id/description"
  951. + android:layout_width="match_parent"
  952. + android:layout_height="wrap_content"
  953. + style="@style/PreferenceSummary" />
  954. +
  955. + <LinearLayout
  956. + android:layout_width="match_parent"
  957. + android:layout_height="wrap_content"
  958. + android:layout_weight="1"
  959. + android:paddingTop="5dp"
  960. + android:layout_gravity="center_vertical" >
  961. +
  962. + <TextView
  963. + android:layout_width="wrap_content"
  964. + android:layout_height="wrap_content"
  965. + android:paddingEnd="5dp"
  966. + style="@style/PreferenceSummary"
  967. + android:text="@string/scripts_item_version"
  968. + android:textStyle="bold" />
  969. +
  970. + <TextView
  971. + android:id="@+id/version"
  972. + android:layout_width="match_parent"
  973. + android:layout_height="wrap_content"
  974. + style="@style/PreferenceSummary" />
  975. +
  976. + </LinearLayout>
  977. +
  978. + <LinearLayout
  979. + android:layout_width="match_parent"
  980. + android:layout_height="wrap_content"
  981. + android:layout_weight="1"
  982. + android:layout_gravity="center_vertical" >
  983. +
  984. + <TextView
  985. + android:layout_width="wrap_content"
  986. + android:layout_height="wrap_content"
  987. + android:paddingEnd="5dp"
  988. + style="@style/PreferenceSummary"
  989. + android:text="@string/scripts_item_filename"
  990. + android:textStyle="bold" />
  991. +
  992. + <TextView
  993. + android:id="@+id/file"
  994. + android:layout_width="match_parent"
  995. + android:layout_height="wrap_content"
  996. + style="@style/PreferenceSummary" />
  997. +
  998. + </LinearLayout>
  999. +
  1000. + <LinearLayout
  1001. + android:id="@+id/url_container"
  1002. + android:layout_width="match_parent"
  1003. + android:layout_height="wrap_content"
  1004. + android:layout_weight="1"
  1005. + android:layout_gravity="center_vertical" >
  1006. +
  1007. + <TextView
  1008. + android:layout_width="wrap_content"
  1009. + android:layout_height="wrap_content"
  1010. + android:paddingEnd="5dp"
  1011. + style="@style/PreferenceSummary"
  1012. + android:text="@string/scripts_item_url"
  1013. + android:textStyle="bold" />
  1014. +
  1015. + <TextView
  1016. + android:id="@+id/url"
  1017. + android:layout_width="match_parent"
  1018. + android:layout_height="wrap_content"
  1019. + android:autoLink="web"
  1020. + android:focusable="true"
  1021. + android:linksClickable="true" />
  1022. +
  1023. + </LinearLayout>
  1024. +
  1025. + </LinearLayout>
  1026. +
  1027. + <org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
  1028. + android:id="@+id/more"
  1029. + android:layout_width="wrap_content"
  1030. + android:layout_height="match_parent"
  1031. + android:paddingStart="@dimen/default_list_row_padding"
  1032. + android:paddingEnd="@dimen/default_list_row_padding"
  1033. + android:background="@null"
  1034. + android:src="@drawable/ic_more_vert_24dp"
  1035. + app:menuMaxWidth="@dimen/pref_scripts_item_popup_width"
  1036. + app:tint="@color/default_icon_color_tint_list"
  1037. + tools:ignore="ContentDescription" />
  1038. +
  1039. + </LinearLayout>
  1040. +
  1041. + <LinearLayout
  1042. + android:id="@+id/error_layout"
  1043. + android:layout_marginStart="0dp"
  1044. + android:paddingStart="@dimen/draggable_list_item_padding"
  1045. + android:paddingEnd="2dp"
  1046. + android:layout_width="match_parent"
  1047. + android:layout_height="wrap_content"
  1048. + style="@style/ListItemContainer">
  1049. +
  1050. + <org.chromium.ui.widget.ChromeImageView
  1051. + android:id="@+id/icon"
  1052. + android:layout_width="40dp"
  1053. + android:layout_height="wrap_content"
  1054. + android:paddingEnd="15dp"
  1055. + android:adjustViewBounds="true"
  1056. + android:importantForAccessibility="no"
  1057. + app:srcCompat="@drawable/ic_error_outline_red_24dp"/>
  1058. +
  1059. + <TextView
  1060. + android:id="@+id/error"
  1061. + android:layout_width="match_parent"
  1062. + android:layout_height="wrap_content"
  1063. + android:textColor="#F00"
  1064. + style="@style/PreferenceSummary" />
  1065. +
  1066. + </LinearLayout>
  1067. +</LinearLayout>
  1068. \ No newline at end of file
  1069. 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
  1070. new file mode 100644
  1071. --- /dev/null
  1072. +++ b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  1073. @@ -0,0 +1,10 @@
  1074. +<?xml version="1.0" encoding="utf-8"?>
  1075. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  1076. + Use of this source code is governed by a BSD-style license that can be
  1077. + found in the LICENSE file. -->
  1078. +
  1079. +<androidx.recyclerview.widget.RecyclerView
  1080. + xmlns:android="http://schemas.android.com/apk/res/android"
  1081. + android:id="@+id/script_list"
  1082. + android:layout_width="match_parent"
  1083. + android:layout_height="wrap_content" />
  1084. \ No newline at end of file
  1085. diff --git a/components/user_scripts/android/java/res/layout/scripts_preference.xml b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  1086. new file mode 100644
  1087. --- /dev/null
  1088. +++ b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  1089. @@ -0,0 +1,40 @@
  1090. +<?xml version="1.0" encoding="utf-8"?>
  1091. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  1092. + Use of this source code is governed by a BSD-style license that can be
  1093. + found in the LICENSE file. -->
  1094. +
  1095. +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  1096. + android:id="@+id/accept_scripts_list_container"
  1097. + style="@style/PreferenceLayout"
  1098. + android:layout_width="match_parent"
  1099. + android:layout_height="wrap_content"
  1100. + android:paddingStart="0dp"
  1101. + android:paddingEnd="0dp"
  1102. + android:padding="0dp"
  1103. + android:orientation="vertical" >
  1104. +
  1105. + <TextView
  1106. + android:layout_width="match_parent"
  1107. + android:layout_height="wrap_content"
  1108. + android:padding="@dimen/draggable_list_item_padding"
  1109. + android:text="@string/scripts_list_description" />
  1110. +
  1111. + <FrameLayout
  1112. + android:id="@android:id/widget_frame"
  1113. + android:layout_width="match_parent"
  1114. + android:layout_height="wrap_content" />
  1115. +
  1116. + <TextView
  1117. + android:id="@+id/add_script"
  1118. + android:layout_width="match_parent"
  1119. + android:layout_height="wrap_content"
  1120. + android:background="?attr/selectableItemBackground"
  1121. + android:clickable="true"
  1122. + android:gravity="center_vertical"
  1123. + android:padding="@dimen/draggable_list_item_padding"
  1124. + android:paddingStart="@dimen/pref_scripts_add_button_padding"
  1125. + android:drawablePadding="@dimen/pref_scripts_add_button_padding"
  1126. + android:text="@string/add_script"
  1127. + style="@style/PreferenceTitle" />
  1128. +
  1129. +</LinearLayout>
  1130. \ No newline at end of file
  1131. diff --git a/components/user_scripts/android/java/res/values/dimens.xml b/components/user_scripts/android/java/res/values/dimens.xml
  1132. new file mode 100755
  1133. --- /dev/null
  1134. +++ b/components/user_scripts/android/java/res/values/dimens.xml
  1135. @@ -0,0 +1,11 @@
  1136. +<?xml version="1.0" encoding="utf-8"?>
  1137. +<!-- Copyright 2014 The Chromium Authors. All rights reserved.
  1138. + Use of this source code is governed by a BSD-style license that can be
  1139. + found in the LICENSE file. -->
  1140. +
  1141. +<resources xmlns:tools="http://schemas.android.com/tools">
  1142. +
  1143. + <dimen name="pref_scripts_add_button_padding">24dp</dimen>
  1144. + <dimen name="pref_scripts_item_popup_width">260dp</dimen>
  1145. +
  1146. +</resources>
  1147. diff --git a/components/user_scripts/android/java/res/xml/userscripts_preferences.xml b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1148. new file mode 100644
  1149. --- /dev/null
  1150. +++ b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1151. @@ -0,0 +1,34 @@
  1152. +<?xml version="1.0" encoding="utf-8"?>
  1153. +<!--
  1154. + This file is part of Bromite.
  1155. +
  1156. + Bromite is free software: you can redistribute it and/or modify
  1157. + it under the terms of the GNU General Public License as published by
  1158. + the Free Software Foundation, either version 3 of the License, or
  1159. + (at your option) any later version.
  1160. +
  1161. + Bromite is distributed in the hope that it will be useful,
  1162. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1163. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1164. + GNU General Public License for more details.
  1165. +
  1166. + You should have received a copy of the GNU General Public License
  1167. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1168. +-->
  1169. +
  1170. +<PreferenceScreen
  1171. + xmlns:android="http://schemas.android.com/apk/res/android"
  1172. + xmlns:app="http://schemas.android.com/apk/res-auto">
  1173. +
  1174. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  1175. + android:key="enabled_switch"
  1176. + android:title="@string/option_userscript_flag"
  1177. + android:summaryOn="@string/option_userscript_flag_on"
  1178. + android:summaryOff="@string/option_userscript_flag_off" />
  1179. +
  1180. + <org.chromium.components.user_scripts.ScriptListPreference
  1181. + android:key="script_list"
  1182. + android:layout="@layout/scripts_preference"
  1183. + android:widgetLayout="@layout/accept_script_list" />
  1184. +
  1185. +</PreferenceScreen>
  1186. 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
  1187. new file mode 100755
  1188. --- /dev/null
  1189. +++ b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  1190. @@ -0,0 +1,87 @@
  1191. +/*
  1192. + This file is part of Bromite.
  1193. +
  1194. + Bromite is free software: you can redistribute it and/or modify
  1195. + it under the terms of the GNU General Public License as published by
  1196. + the Free Software Foundation, either version 3 of the License, or
  1197. + (at your option) any later version.
  1198. +
  1199. + Bromite is distributed in the hope that it will be useful,
  1200. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1201. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1202. + GNU General Public License for more details.
  1203. +
  1204. + You should have received a copy of the GNU General Public License
  1205. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1206. +*/
  1207. +
  1208. +package org.chromium.chrome.browser.user_scripts;
  1209. +
  1210. +import android.content.Context;
  1211. +import android.content.Intent;
  1212. +import android.provider.Browser;
  1213. +import android.provider.MediaStore;
  1214. +import android.net.Uri;
  1215. +
  1216. +import org.chromium.base.ContextUtils;
  1217. +import org.chromium.base.ContentUriUtils;
  1218. +import org.chromium.base.IntentUtils;
  1219. +
  1220. +import org.chromium.chrome.browser.IntentHandler;
  1221. +import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  1222. +import org.chromium.components.browser_ui.settings.SettingsLauncher;
  1223. +
  1224. +import org.chromium.components.user_scripts.UserScriptsPreferences;
  1225. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1226. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1227. +
  1228. +public class UserScriptsUtils implements IUserScriptsUtils
  1229. +{
  1230. + private static UserScriptsUtils instance;
  1231. +
  1232. + private UserScriptsUtils() {}
  1233. +
  1234. + public static void Initialize() {
  1235. + instance = new UserScriptsUtils();
  1236. + UserScriptsBridge.registerUtils(instance);
  1237. + }
  1238. +
  1239. + public static UserScriptsUtils getInstance() {
  1240. + if (instance == null) Initialize();
  1241. + return instance;
  1242. + }
  1243. +
  1244. + public boolean openFile(String filePath, String mimeType, String downloadGuid,
  1245. + String originalUrl, String referrer, Uri contentUri) {
  1246. + if (UserScriptsBridge.isEnabled() == false) return false;
  1247. +
  1248. + Context context = ContextUtils.getApplicationContext();
  1249. +
  1250. + String visibleName = filePath;
  1251. + if (ContentUriUtils.isContentUri(visibleName)) {
  1252. + visibleName = ContentUriUtils.getDisplayName(contentUri, context,
  1253. + MediaStore.MediaColumns.DISPLAY_NAME);
  1254. + }
  1255. +
  1256. + if (visibleName.toUpperCase().endsWith(".USER.JS") == false) return false;
  1257. +
  1258. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  1259. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  1260. + context, UserScriptsPreferences.class.getName(),
  1261. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  1262. + IntentUtils.safeStartActivity(context, intent);
  1263. +
  1264. + return true;
  1265. + }
  1266. +
  1267. + public void openSourceFile(String scriptKey) {
  1268. + Context context = ContextUtils.getApplicationContext();
  1269. +
  1270. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("chrome://user-scripts/?key=" + scriptKey));
  1271. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1272. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1273. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1274. + intent.setPackage(context.getPackageName());
  1275. + IntentHandler.startChromeLauncherActivityForTrustedIntent(intent);
  1276. + }
  1277. +}
  1278. 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
  1279. new file mode 100644
  1280. --- /dev/null
  1281. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1282. @@ -0,0 +1,90 @@
  1283. +// Copyright 2019 The Chromium Authors. All rights reserved.
  1284. +// Use of this source code is governed by a BSD-style license that can be
  1285. +// found in the LICENSE file.
  1286. +
  1287. +package org.chromium.components.user_scripts;
  1288. +
  1289. +import android.annotation.TargetApi;
  1290. +import android.app.Activity;
  1291. +import android.content.Context;
  1292. +import android.content.Intent;
  1293. +import android.content.IntentSender;
  1294. +import android.os.Build;
  1295. +import android.view.View;
  1296. +
  1297. +import androidx.fragment.app.Fragment;
  1298. +
  1299. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  1300. +import org.chromium.ui.base.ImmutableWeakReference;
  1301. +import org.chromium.ui.base.IntentRequestTracker;
  1302. +import org.chromium.ui.base.IntentRequestTracker.Delegate;
  1303. +import org.chromium.ui.base.WindowAndroid;
  1304. +
  1305. +import java.lang.ref.WeakReference;
  1306. +
  1307. +import org.chromium.ui.permissions.ActivityAndroidPermissionDelegate;
  1308. +
  1309. +/**
  1310. + * Implements intent sending for a fragment based window. This should be created when
  1311. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  1312. + */
  1313. +public class FragmentWindowAndroid extends WindowAndroid {
  1314. + private Fragment mFragment;
  1315. +
  1316. + private static class TrackerDelegateImpl implements Delegate {
  1317. + private final Fragment mFragment;
  1318. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  1319. + // every getActivity call. It is not needed for correctness.
  1320. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  1321. +
  1322. + /**
  1323. + * Create an instance of delegate for the given fragment that will own the
  1324. + * IntentRequestTracker.
  1325. + * @param fragment The fragment that owns the IntentRequestTracker.
  1326. + */
  1327. + private TrackerDelegateImpl(Fragment fragment) {
  1328. + mFragment = fragment;
  1329. + }
  1330. +
  1331. + @Override
  1332. + public boolean startActivityForResult(Intent intent, int requestCode) {
  1333. + mFragment.startActivityForResult(intent, requestCode, null);
  1334. + return true;
  1335. + }
  1336. +
  1337. + @Override
  1338. + public boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  1339. + try {
  1340. + mFragment.startIntentSenderForResult(
  1341. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  1342. + } catch (IntentSender.SendIntentException e) {
  1343. + return false;
  1344. + }
  1345. + return true;
  1346. + }
  1347. +
  1348. + @Override
  1349. + public void finishActivity(int requestCode) {
  1350. + Activity activity = getActivity().get();
  1351. + if (activity == null) return;
  1352. + activity.finishActivity(requestCode);
  1353. + }
  1354. +
  1355. + @Override
  1356. + public final WeakReference<Activity> getActivity() {
  1357. + if (mActivityWeakRefHolder == null
  1358. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1359. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1360. + }
  1361. + return mActivityWeakRefHolder;
  1362. + }
  1363. + }
  1364. +
  1365. + FragmentWindowAndroid(Context context, Fragment fragment) {
  1366. + super(context, IntentRequestTracker.createFromDelegate(new TrackerDelegateImpl(fragment)));
  1367. + mFragment = fragment;
  1368. +
  1369. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  1370. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  1371. + }
  1372. +}
  1373. 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
  1374. new file mode 100644
  1375. --- /dev/null
  1376. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1377. @@ -0,0 +1,22 @@
  1378. +/*
  1379. + This file is part of Bromite.
  1380. +
  1381. + Bromite is free software: you can redistribute it and/or modify
  1382. + it under the terms of the GNU General Public License as published by
  1383. + the Free Software Foundation, either version 3 of the License, or
  1384. + (at your option) any later version.
  1385. +
  1386. + Bromite is distributed in the hope that it will be useful,
  1387. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1388. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1389. + GNU General Public License for more details.
  1390. +
  1391. + You should have received a copy of the GNU General Public License
  1392. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1393. +*/
  1394. +
  1395. +package org.chromium.components.user_scripts;
  1396. +
  1397. +public interface IUserScriptsUtils {
  1398. + public void openSourceFile(String scriptKey);
  1399. +}
  1400. \ No newline at end of file
  1401. 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
  1402. new file mode 100644
  1403. --- /dev/null
  1404. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1405. @@ -0,0 +1,37 @@
  1406. +/*
  1407. + This file is part of Bromite.
  1408. +
  1409. + Bromite is free software: you can redistribute it and/or modify
  1410. + it under the terms of the GNU General Public License as published by
  1411. + the Free Software Foundation, either version 3 of the License, or
  1412. + (at your option) any later version.
  1413. +
  1414. + Bromite is distributed in the hope that it will be useful,
  1415. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1416. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1417. + GNU General Public License for more details.
  1418. +
  1419. + You should have received a copy of the GNU General Public License
  1420. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1421. +*/
  1422. +
  1423. +package org.chromium.components.user_scripts;
  1424. +
  1425. +import java.time.LocalDateTime;
  1426. +
  1427. +public class ScriptInfo {
  1428. + public String Key;
  1429. + public String Name;
  1430. + public String Description;
  1431. + public String Version;
  1432. + public String FilePath;
  1433. + public String UrlSource;
  1434. +
  1435. + public boolean Enabled;
  1436. + public LocalDateTime InstallTime;
  1437. +
  1438. + public String ParserError;
  1439. + public boolean ForceDisabled;
  1440. +
  1441. + public ScriptInfo() {}
  1442. +}
  1443. 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
  1444. new file mode 100644
  1445. --- /dev/null
  1446. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1447. @@ -0,0 +1,163 @@
  1448. +/*
  1449. + This file is part of Bromite.
  1450. +
  1451. + Bromite is free software: you can redistribute it and/or modify
  1452. + it under the terms of the GNU General Public License as published by
  1453. + the Free Software Foundation, either version 3 of the License, or
  1454. + (at your option) any later version.
  1455. +
  1456. + Bromite is distributed in the hope that it will be useful,
  1457. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1458. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1459. + GNU General Public License for more details.
  1460. +
  1461. + You should have received a copy of the GNU General Public License
  1462. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1463. +*/
  1464. +
  1465. +package org.chromium.components.user_scripts;
  1466. +
  1467. +import android.content.Context;
  1468. +import android.view.LayoutInflater;
  1469. +import android.view.MotionEvent;
  1470. +import android.view.View;
  1471. +import android.view.ViewGroup;
  1472. +import android.view.accessibility.AccessibilityManager;
  1473. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1474. +import android.widget.ImageView;
  1475. +import android.widget.TextView;
  1476. +import android.widget.Switch;
  1477. +import android.widget.CompoundButton;
  1478. +import android.widget.LinearLayout;
  1479. +
  1480. +import androidx.annotation.DrawableRes;
  1481. +import androidx.annotation.NonNull;
  1482. +import androidx.core.view.ViewCompat;
  1483. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1484. +
  1485. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1486. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1487. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1488. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1489. +import org.chromium.ui.widget.ChromeImageView;
  1490. +
  1491. +import java.util.ArrayList;
  1492. +import java.util.List;
  1493. +
  1494. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1495. +
  1496. + class ItemClickListener {
  1497. + void onScriptOnOff(boolean Enabled) {}
  1498. + void onScriptClicked() {}
  1499. + }
  1500. +
  1501. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1502. + private TextView mTitle;
  1503. + private TextView mDescription;
  1504. + private TextView mVersion;
  1505. + private TextView mFile;
  1506. + private TextView mUrl;
  1507. + private TextView mError;
  1508. + private Switch mSwitch;
  1509. + private ChromeImageView mIcon;
  1510. + private LinearLayout mErrorLayout;
  1511. + private LinearLayout mUrlContainer;
  1512. +
  1513. + private ListMenuButton mMoreButton;
  1514. +
  1515. + private CompoundButton.OnCheckedChangeListener mOnOffListener;
  1516. +
  1517. + ScriptInfoRowViewHolder(View view) {
  1518. + super(view);
  1519. +
  1520. + mSwitch = view.findViewById(R.id.switch_widget);
  1521. + mTitle = view.findViewById(R.id.title);
  1522. + mDescription = view.findViewById(R.id.description);
  1523. + mVersion = view.findViewById(R.id.version);
  1524. + mFile = view.findViewById(R.id.file);
  1525. + mUrl = view.findViewById(R.id.url);
  1526. + mUrlContainer = view.findViewById(R.id.url_container);
  1527. + mError = view.findViewById(R.id.error);
  1528. + mIcon = view.findViewById(R.id.icon);
  1529. + mErrorLayout = view.findViewById(R.id.error_layout);
  1530. +
  1531. + mMoreButton = view.findViewById(R.id.more);
  1532. + }
  1533. +
  1534. + protected void updateScriptInfo(ScriptInfo item) {
  1535. + mSwitch.setOnCheckedChangeListener(null);
  1536. + mSwitch.setChecked(item.Enabled);
  1537. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1538. +
  1539. + mSwitch.setEnabled(true);
  1540. + if (item.ForceDisabled) {
  1541. + mSwitch.setEnabled(false);
  1542. + }
  1543. +
  1544. + mTitle.setText(item.Name);
  1545. + mDescription.setText(item.Description);
  1546. + mVersion.setText(item.Version);
  1547. + mFile.setText(item.Key);
  1548. + mUrl.setText(item.UrlSource);
  1549. + mError.setText(item.ParserError);
  1550. +
  1551. + mUrl.setVisibility(View.VISIBLE);
  1552. + if (item.UrlSource == null || item.UrlSource.isEmpty()) {
  1553. + mUrlContainer.setVisibility(View.GONE);
  1554. + }
  1555. + mErrorLayout.setVisibility(View.VISIBLE);
  1556. + if (item.ParserError == null || item.ParserError.isEmpty()) {
  1557. + mErrorLayout.setVisibility(View.GONE);
  1558. + }
  1559. + }
  1560. +
  1561. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1562. + mMoreButton.setVisibility(View.VISIBLE);
  1563. + mMoreButton.setDelegate(delegate);
  1564. + // Set item row end padding 0 when MenuButton is visible.
  1565. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1566. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1567. + }
  1568. +
  1569. + void setItemListener(@NonNull ItemClickListener listener) {
  1570. + mOnOffListener = (buttonView, isChecked) -> listener.onScriptOnOff(isChecked);
  1571. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1572. + itemView.setOnClickListener(view -> listener.onScriptClicked());
  1573. + }
  1574. + }
  1575. +
  1576. + ScriptListBaseAdapter(Context context) {
  1577. + super(context);
  1578. + }
  1579. +
  1580. + @Override
  1581. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1582. + View row = LayoutInflater.from(viewGroup.getContext())
  1583. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1584. + return new ScriptInfoRowViewHolder(row);
  1585. + }
  1586. +
  1587. + @Override
  1588. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1589. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1590. + }
  1591. +
  1592. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1593. + mElements = new ArrayList<>(values);
  1594. + notifyDataSetChanged();
  1595. + }
  1596. +
  1597. + @Override
  1598. + protected void setOrder(List<ScriptInfo> order) {
  1599. + }
  1600. +
  1601. + @Override
  1602. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1603. + return isPassivelyDraggable(viewHolder);
  1604. + }
  1605. +
  1606. + @Override
  1607. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1608. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1609. + }
  1610. +}
  1611. 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
  1612. new file mode 100644
  1613. --- /dev/null
  1614. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1615. @@ -0,0 +1,171 @@
  1616. +/*
  1617. + This file is part of Bromite.
  1618. +
  1619. + Bromite is free software: you can redistribute it and/or modify
  1620. + it under the terms of the GNU General Public License as published by
  1621. + the Free Software Foundation, either version 3 of the License, or
  1622. + (at your option) any later version.
  1623. +
  1624. + Bromite is distributed in the hope that it will be useful,
  1625. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1626. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1627. + GNU General Public License for more details.
  1628. +
  1629. + You should have received a copy of the GNU General Public License
  1630. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1631. +*/
  1632. +
  1633. +package org.chromium.components.user_scripts;
  1634. +
  1635. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1636. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1637. +
  1638. +import android.content.Context;
  1639. +import android.content.Intent;
  1640. +import android.provider.Browser;
  1641. +import android.net.Uri;
  1642. +import android.util.AttributeSet;
  1643. +import android.widget.TextView;
  1644. +import android.widget.Toast;
  1645. +
  1646. +import androidx.preference.Preference;
  1647. +import androidx.preference.PreferenceViewHolder;
  1648. +import androidx.recyclerview.widget.DividerItemDecoration;
  1649. +import androidx.recyclerview.widget.LinearLayoutManager;
  1650. +import androidx.recyclerview.widget.RecyclerView;
  1651. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1652. +
  1653. +import org.chromium.ui.base.WindowAndroid;
  1654. +import org.chromium.ui.base.ActivityWindowAndroid;
  1655. +
  1656. +import org.chromium.base.ApplicationStatus;
  1657. +import org.chromium.base.ContextUtils;
  1658. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1659. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1660. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1661. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1662. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1663. +
  1664. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1665. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1666. +
  1667. +import java.util.List;
  1668. +
  1669. +public class ScriptListPreference extends Preference {
  1670. + private static class ScriptListAdapter
  1671. + extends ScriptListBaseAdapter {
  1672. + private final Context mContext;
  1673. +
  1674. + ScriptListAdapter(Context context) {
  1675. + super(context);
  1676. + mContext = context;
  1677. + }
  1678. +
  1679. + @Override
  1680. + public void onBindViewHolder(ViewHolder holder, int position) {
  1681. + super.onBindViewHolder(holder, position);
  1682. +
  1683. + final ScriptInfo info = getItemByPosition(position);
  1684. +
  1685. + ModelList menuItems = new ModelList();
  1686. +
  1687. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1688. + menuItems.add(buildMenuListItem(R.string.scripts_view_source, 0, 0,
  1689. + info.ParserError == null || info.ParserError.isEmpty()));
  1690. +
  1691. + ListMenu.Delegate delegate = (model) -> {
  1692. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1693. + if (textId == R.string.remove) {
  1694. + UserScriptsBridge.RemoveScript(info.Key);
  1695. + } else if (textId == R.string.scripts_view_source) {
  1696. + UserScriptsBridge.getUtils().openSourceFile(info.Key);
  1697. + }
  1698. + };
  1699. + ((ScriptInfoRowViewHolder) holder)
  1700. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1701. + ((ScriptInfoRowViewHolder) holder)
  1702. + .setItemListener(new ScriptListBaseAdapter.ItemClickListener() {
  1703. + @Override
  1704. + public void onScriptOnOff(boolean Enabled) {
  1705. + UserScriptsBridge.SetScriptEnabled(info.Key, Enabled);
  1706. + }
  1707. +
  1708. + @Override
  1709. + public void onScriptClicked() {}
  1710. + });
  1711. + }
  1712. +
  1713. + // @Override
  1714. + public void onDataUpdated(boolean enabled) {
  1715. + List<ScriptInfo> list = UserScriptsBridge.getUserScriptItems();
  1716. + if (enabled == false) {
  1717. + for (ScriptInfo script : list) {
  1718. + script.ForceDisabled = true;
  1719. + }
  1720. + }
  1721. + setDisplayedScriptInfo(list);
  1722. + }
  1723. + }
  1724. +
  1725. + private TextView mAddButton;
  1726. + private RecyclerView mRecyclerView;
  1727. + private ScriptListAdapter mAdapter;
  1728. + private FragmentWindowAndroid mWindowAndroid;
  1729. +
  1730. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1731. + super(context, attrs);
  1732. + mAdapter = new ScriptListAdapter(context);
  1733. + }
  1734. +
  1735. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1736. + mWindowAndroid = windowAndroid;
  1737. + }
  1738. +
  1739. + @Override
  1740. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1741. + super.onBindViewHolder(holder);
  1742. +
  1743. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1744. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1745. + TintedDrawable.constructTintedDrawable(
  1746. + getContext(), R.drawable.plus, R.color.default_control_color_active_baseline),
  1747. + null, null, null);
  1748. + mAddButton.setOnClickListener(view -> {
  1749. + UserScriptsBridge.SelectAndAddScriptFromFile(mWindowAndroid);
  1750. + });
  1751. +
  1752. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1753. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1754. + mRecyclerView.setLayoutManager(layoutManager);
  1755. + mRecyclerView.addItemDecoration(
  1756. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1757. + mRecyclerView.setEnabled(this.isEnabled());
  1758. + UserScriptsBridge.RegisterLoadCallback(this);
  1759. +
  1760. + // We do not want the RecyclerView to be announced by screen readers every time
  1761. + // the view is bound.
  1762. + if (mRecyclerView.getAdapter() != mAdapter) {
  1763. + mRecyclerView.setAdapter(mAdapter);
  1764. + // Initialize script list.
  1765. + mAdapter.onDataUpdated(this.isEnabled());
  1766. + }
  1767. + }
  1768. +
  1769. + @Override
  1770. + public void setEnabled (boolean enabled) {
  1771. + super.setEnabled(enabled);
  1772. + if (mRecyclerView != null) mRecyclerView.setEnabled(enabled);
  1773. + NotifyScriptsChanged();
  1774. + }
  1775. +
  1776. + public void NotifyScriptsChanged() {
  1777. + mAdapter.onDataUpdated(this.isEnabled());
  1778. + }
  1779. +
  1780. + public void OnUserScriptLoaded(boolean result, String error) {
  1781. + if (result == false) {
  1782. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1783. + toast.show();
  1784. + }
  1785. + }
  1786. +}
  1787. 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
  1788. new file mode 100644
  1789. --- /dev/null
  1790. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1791. @@ -0,0 +1,212 @@
  1792. +/*
  1793. + This file is part of Bromite.
  1794. +
  1795. + Bromite is free software: you can redistribute it and/or modify
  1796. + it under the terms of the GNU General Public License as published by
  1797. + the Free Software Foundation, either version 3 of the License, or
  1798. + (at your option) any later version.
  1799. +
  1800. + Bromite is distributed in the hope that it will be useful,
  1801. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1802. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1803. + GNU General Public License for more details.
  1804. +
  1805. + You should have received a copy of the GNU General Public License
  1806. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1807. +*/
  1808. +
  1809. +package org.chromium.components.user_scripts;
  1810. +
  1811. +import java.util.ArrayList;
  1812. +import java.util.List;
  1813. +import java.lang.ref.WeakReference;
  1814. +
  1815. +import org.json.JSONArray;
  1816. +import org.json.JSONException;
  1817. +import org.json.JSONObject;
  1818. +
  1819. +import android.content.Context;
  1820. +import android.content.Intent;
  1821. +import android.net.Uri;
  1822. +import android.provider.MediaStore;
  1823. +import androidx.annotation.Nullable;
  1824. +import android.app.AlertDialog;
  1825. +import android.content.DialogInterface;
  1826. +
  1827. +import org.chromium.base.annotations.CalledByNative;
  1828. +import org.chromium.base.annotations.JNINamespace;
  1829. +import org.chromium.base.annotations.NativeMethods;
  1830. +import org.chromium.base.ContentUriUtils;
  1831. +import org.chromium.base.Log;
  1832. +import org.chromium.ui.base.WindowAndroid;
  1833. +
  1834. +import org.chromium.components.user_scripts.ScriptListPreference;
  1835. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1836. +
  1837. +@JNINamespace("user_scripts")
  1838. +public class UserScriptsBridge {
  1839. + private static final String TAG = "UserScript";
  1840. +
  1841. + static WeakReference<ScriptListPreference> observer;
  1842. +
  1843. + private static IUserScriptsUtils utilInstance;
  1844. +
  1845. + public static void registerUtils(IUserScriptsUtils instance) {
  1846. + utilInstance = instance;
  1847. + }
  1848. +
  1849. + public static IUserScriptsUtils getUtils() {
  1850. + return utilInstance;
  1851. + }
  1852. +
  1853. + public static boolean isEnabled() {
  1854. + return UserScriptsBridgeJni.get().isEnabled();
  1855. + }
  1856. +
  1857. + public static void setEnabled(boolean enabled) {
  1858. + UserScriptsBridgeJni.get().setEnabled(enabled);
  1859. + }
  1860. +
  1861. + public static void RemoveScript(String key) {
  1862. + UserScriptsBridgeJni.get().removeScript(key);
  1863. + }
  1864. +
  1865. + public static void SetScriptEnabled(String key,
  1866. + boolean enabled) {
  1867. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1868. + }
  1869. +
  1870. + public static void Reload() {
  1871. + UserScriptsBridgeJni.get().reload();
  1872. + }
  1873. +
  1874. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1875. + Context context = window.getContext().get();
  1876. +
  1877. + Intent fileSelector = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  1878. + fileSelector.addCategory(Intent.CATEGORY_OPENABLE);
  1879. + fileSelector.setType("*/*");
  1880. + fileSelector.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  1881. +
  1882. + window.showIntent(fileSelector,
  1883. + new WindowAndroid.IntentCallback() {
  1884. + @Override
  1885. + public void onIntentCompleted(int resultCode, Intent data) {
  1886. + if (data == null) return;
  1887. + Uri filePath = data.getData();
  1888. + TryToInstall(context, filePath.toString());
  1889. + }
  1890. + },
  1891. + null);
  1892. + }
  1893. +
  1894. + public static void TryToInstall(Context context, String ScriptFullPath) {
  1895. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1896. + @Override
  1897. + public void onClick(DialogInterface dialog, int which) {
  1898. + switch (which){
  1899. + case DialogInterface.BUTTON_POSITIVE:
  1900. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1901. + break;
  1902. +
  1903. + case DialogInterface.BUTTON_NEGATIVE:
  1904. + break;
  1905. + }
  1906. + }
  1907. + };
  1908. +
  1909. + String scriptName = ScriptFullPath;
  1910. + if (ContentUriUtils.isContentUri(scriptName)) {
  1911. + scriptName = ContentUriUtils.getFilePathFromContentUri(Uri.parse(scriptName));
  1912. + if (scriptName == null) {
  1913. + // fallback to content uri name if fail
  1914. + scriptName = ContentUriUtils.getDisplayName(Uri.parse(ScriptFullPath), context,
  1915. + MediaStore.MediaColumns.DISPLAY_NAME);
  1916. + }
  1917. + }
  1918. +
  1919. + String message = context.getString(R.string.ask_to_install, scriptName);
  1920. +
  1921. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1922. + builder.setMessage(message)
  1923. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1924. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1925. + .show();
  1926. + }
  1927. +
  1928. + public static List<ScriptInfo> getUserScriptItems() {
  1929. + List<ScriptInfo> list = new ArrayList<>();
  1930. + try {
  1931. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1932. +
  1933. + JSONObject jsonObject = new JSONObject(json);
  1934. +
  1935. + JSONArray scripts = jsonObject.names();
  1936. + if (scripts != null) {
  1937. + Log.i(TAG, "User Scripts Loaded: %s", json);
  1938. + Log.i(TAG, "Totals scripts: %s", Integer.toString(scripts.length()));
  1939. + for (int i = 0; i < scripts.length(); i++) {
  1940. + String key = (String) scripts.get(i);
  1941. + JSONObject script = jsonObject.getJSONObject(key);
  1942. +
  1943. + ScriptInfo si = new ScriptInfo();
  1944. + si.Key = key;
  1945. + list.add(si);
  1946. +
  1947. + if(script.has("name")) si.Name = script.getString("name");
  1948. + if(script.has("description")) si.Description = script.getString("description");
  1949. + if(script.has("version")) si.Version = script.getString("version");
  1950. + if(script.has("file_path")) si.FilePath = script.getString("file_path");
  1951. + if(script.has("url_source")) si.UrlSource = script.getString("url_source");
  1952. + if(script.has("parser_error")) si.ParserError = script.getString("parser_error");
  1953. + if(script.has("force_disabled")) si.ForceDisabled = script.getBoolean("force_disabled");;
  1954. + si.Enabled = script.getBoolean("enabled");
  1955. + }
  1956. + } else {
  1957. + Log.i(TAG, "User Scripts list empty");
  1958. + }
  1959. + } catch (Exception e) {
  1960. + Log.e(TAG, "User Scripts Load Error", e.toString());
  1961. + }
  1962. + return list;
  1963. + }
  1964. +
  1965. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1966. + UserScriptsBridgeJni.get().registerLoadCallback();
  1967. + observer = new WeakReference<ScriptListPreference>(caller);
  1968. + }
  1969. +
  1970. + @CalledByNative
  1971. + private static void shouldRefreshUserScriptList() {
  1972. + ScriptListPreference reference = observer.get();
  1973. + if (reference != null) {
  1974. + reference.NotifyScriptsChanged();
  1975. + }
  1976. + }
  1977. +
  1978. + @CalledByNative
  1979. + private static void onUserScriptLoaded(boolean result, String error) {
  1980. + ScriptListPreference reference = observer.get();
  1981. + if (reference != null) {
  1982. + reference.OnUserScriptLoaded(result, error);
  1983. + }
  1984. + }
  1985. +
  1986. + @NativeMethods
  1987. + interface Natives {
  1988. + boolean isEnabled();
  1989. + void setEnabled(boolean enabled);
  1990. +
  1991. + String getScriptsInfo();
  1992. +
  1993. + void removeScript(String scriptKey);
  1994. + void setScriptEnabled(String scriptKey, boolean enabled);
  1995. +
  1996. + void reload();
  1997. + void selectAndAddScriptFromFile(WindowAndroid window);
  1998. + void tryToInstall(String scriptFullPath);
  1999. +
  2000. + void registerLoadCallback();
  2001. + }
  2002. +
  2003. +}
  2004. 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
  2005. new file mode 100755
  2006. --- /dev/null
  2007. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  2008. @@ -0,0 +1,116 @@
  2009. +/*
  2010. + This file is part of Bromite.
  2011. +
  2012. + Bromite is free software: you can redistribute it and/or modify
  2013. + it under the terms of the GNU General Public License as published by
  2014. + the Free Software Foundation, either version 3 of the License, or
  2015. + (at your option) any later version.
  2016. +
  2017. + Bromite is distributed in the hope that it will be useful,
  2018. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2019. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2020. + GNU General Public License for more details.
  2021. +
  2022. + You should have received a copy of the GNU General Public License
  2023. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2024. +*/
  2025. +
  2026. +package org.chromium.components.user_scripts;
  2027. +
  2028. +import android.app.Activity;
  2029. +import android.content.Context;
  2030. +import android.content.Intent;
  2031. +import android.os.Bundle;
  2032. +import android.provider.Browser;
  2033. +import android.net.Uri;
  2034. +import android.view.MenuItem;
  2035. +import android.view.View;
  2036. +
  2037. +import androidx.preference.Preference;
  2038. +import androidx.preference.PreferenceFragmentCompat;
  2039. +
  2040. +import org.chromium.base.Log;
  2041. +import org.chromium.ui.base.WindowAndroid;
  2042. +import org.chromium.ui.base.ActivityWindowAndroid;
  2043. +
  2044. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  2045. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  2046. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  2047. +
  2048. +import org.chromium.components.user_scripts.UserScriptsBridge;
  2049. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  2050. +
  2051. +public class UserScriptsPreferences
  2052. + extends PreferenceFragmentCompat
  2053. + implements SettingsUtils.ISupportHelpAndFeedback {
  2054. +
  2055. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  2056. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  2057. +
  2058. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  2059. +
  2060. + private FragmentWindowAndroid mWindowAndroid;
  2061. +
  2062. + @Override
  2063. + public void onDestroy() {
  2064. + if (mWindowAndroid != null) mWindowAndroid.destroy();
  2065. + super.onDestroy();
  2066. + }
  2067. +
  2068. + @Override
  2069. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  2070. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  2071. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  2072. +
  2073. + ChromeSwitchPreference enabledSwitch =
  2074. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  2075. + ScriptListPreference listPreference =
  2076. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  2077. +
  2078. + boolean enabled = UserScriptsBridge.isEnabled();
  2079. + enabledSwitch.setChecked(enabled);
  2080. + listPreference.setEnabled(enabled);
  2081. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  2082. + UserScriptsBridge.setEnabled((boolean) newValue);
  2083. + listPreference.setEnabled((boolean) newValue);
  2084. + return true;
  2085. + });
  2086. +
  2087. + mWindowAndroid = new FragmentWindowAndroid(getContext(), this);
  2088. + listPreference.setWindowAndroid(mWindowAndroid);
  2089. + }
  2090. +
  2091. + @Override
  2092. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  2093. + // handle picker callback from SelectFileDialog
  2094. + mWindowAndroid.getIntentRequestTracker().onActivityResult(requestCode, resultCode, data);
  2095. + }
  2096. +
  2097. + public void onHelpAndFeebackPressed() {
  2098. + Context context = getContext();
  2099. +
  2100. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  2101. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  2102. + // the user presses 'back' button.
  2103. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  2104. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  2105. + intent.setPackage(context.getPackageName());
  2106. + context.startActivity(intent);
  2107. + }
  2108. +
  2109. + public static Bundle createFragmentArgsForInstall(String filePath) {
  2110. + Bundle fragmentArgs = new Bundle();
  2111. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  2112. + return fragmentArgs;
  2113. + }
  2114. +
  2115. + @Override
  2116. + public void onActivityCreated(Bundle savedInstanceState) {
  2117. + super.onActivityCreated(savedInstanceState);
  2118. +
  2119. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  2120. + if (scriptToInstall != null) {
  2121. + UserScriptsBridge.TryToInstall(getContext(), scriptToInstall);
  2122. + }
  2123. + }
  2124. +}
  2125. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  2126. new file mode 100644
  2127. --- /dev/null
  2128. +++ b/components/user_scripts/android/java_sources.gni
  2129. @@ -0,0 +1,18 @@
  2130. +# This file is part of Bromite.
  2131. +
  2132. +# Bromite is free software: you can redistribute it and/or modify
  2133. +# it under the terms of the GNU General Public License as published by
  2134. +# the Free Software Foundation, either version 3 of the License, or
  2135. +# (at your option) any later version.
  2136. +
  2137. +# Bromite is distributed in the hope that it will be useful,
  2138. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2139. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2140. +# GNU General Public License for more details.
  2141. +
  2142. +# You should have received a copy of the GNU General Public License
  2143. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2144. +
  2145. +userscripts_java_sources = [
  2146. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  2147. +]
  2148. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  2149. new file mode 100644
  2150. --- /dev/null
  2151. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  2152. @@ -0,0 +1,173 @@
  2153. +/*
  2154. + This file is part of Bromite.
  2155. +
  2156. + Bromite is free software: you can redistribute it and/or modify
  2157. + it under the terms of the GNU General Public License as published by
  2158. + the Free Software Foundation, either version 3 of the License, or
  2159. + (at your option) any later version.
  2160. +
  2161. + Bromite is distributed in the hope that it will be useful,
  2162. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2163. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2164. + GNU General Public License for more details.
  2165. +
  2166. + You should have received a copy of the GNU General Public License
  2167. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2168. +*/
  2169. +
  2170. +#include <jni.h>
  2171. +#include <algorithm>
  2172. +#include <string>
  2173. +#include <vector>
  2174. +#include <sstream>
  2175. +#include <iterator>
  2176. +
  2177. +#include "base/android/callback_android.h"
  2178. +#include "base/android/jni_android.h"
  2179. +#include "base/android/jni_array.h"
  2180. +#include "base/android/jni_string.h"
  2181. +#include "base/android/scoped_java_ref.h"
  2182. +#include "ui/android/window_android.h"
  2183. +
  2184. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  2185. +#include "../browser/userscripts_browser_client.h"
  2186. +#include "user_scripts_bridge.h"
  2187. +
  2188. +using base::android::AttachCurrentThread;
  2189. +using base::android::ConvertJavaStringToUTF8;
  2190. +using base::android::ConvertUTF16ToJavaString;
  2191. +using base::android::ConvertUTF8ToJavaString;
  2192. +using base::android::JavaParamRef;
  2193. +using base::android::JavaRef;
  2194. +using base::android::ScopedJavaGlobalRef;
  2195. +using base::android::ScopedJavaLocalRef;
  2196. +using content::BrowserContext;
  2197. +
  2198. +namespace {
  2199. +
  2200. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  2201. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  2202. +}
  2203. +
  2204. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  2205. + private:
  2206. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  2207. + content::BrowserContext* browser_context) override {
  2208. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  2209. + }
  2210. +
  2211. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  2212. + bool result, const std::string& error) override {
  2213. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  2214. + result, error);
  2215. + }
  2216. +
  2217. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  2218. +};
  2219. +
  2220. +CallbackObserver* g_userscripts_loader_observer = NULL;
  2221. +
  2222. +}
  2223. +
  2224. +namespace user_scripts {
  2225. +
  2226. +static jboolean JNI_UserScriptsBridge_IsEnabled(
  2227. + JNIEnv* env) {
  2228. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2229. + if (client == NULL) return false;
  2230. + return client->GetPrefs()->IsEnabled();
  2231. +}
  2232. +
  2233. +static void JNI_UserScriptsBridge_SetEnabled(
  2234. + JNIEnv* env,
  2235. + jboolean is_enabled) {
  2236. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2237. + if (client == NULL) return;
  2238. + client->GetPrefs()->SetEnabled(is_enabled);
  2239. + client->GetLoader()->StartLoad();
  2240. +}
  2241. +
  2242. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  2243. + JNIEnv* env) {
  2244. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2245. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  2246. +
  2247. + std::string json = client->GetPrefs()->GetScriptsInfo();
  2248. + return ConvertUTF8ToJavaString(env, json);
  2249. +}
  2250. +
  2251. +static void JNI_UserScriptsBridge_RemoveScript(
  2252. + JNIEnv* env,
  2253. + const JavaParamRef<jstring>& jscript_key) {
  2254. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2255. + if (client == NULL) return;
  2256. +
  2257. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2258. + client->GetLoader()->RemoveScript(script_key);
  2259. +}
  2260. +
  2261. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  2262. + JNIEnv* env,
  2263. + const JavaParamRef<jstring>& jscript_key,
  2264. + jboolean is_enabled) {
  2265. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2266. + if (client == NULL) return;
  2267. +
  2268. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2269. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  2270. +}
  2271. +
  2272. +static void JNI_UserScriptsBridge_Reload(
  2273. + JNIEnv* env) {
  2274. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2275. + if (client == NULL) return;
  2276. +
  2277. + client->GetLoader()->StartLoad();
  2278. + user_scripts::ShouldRefreshUserScriptList(env);
  2279. +}
  2280. +
  2281. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  2282. + JNIEnv* env,
  2283. + const JavaParamRef<jobject>& jwindow_android) {
  2284. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2285. + if (client == NULL) return;
  2286. +
  2287. + client->GetLoader()->SelectAndAddScriptFromFile(
  2288. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  2289. +}
  2290. +
  2291. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  2292. + const JavaParamRef<jstring>& jscript_path) {
  2293. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2294. + if (client == NULL) return;
  2295. +
  2296. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  2297. + base::FilePath path(script_path);
  2298. +
  2299. + client->GetLoader()->TryToInstall(path);
  2300. +}
  2301. +
  2302. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  2303. + JNIEnv* env) {
  2304. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2305. + if (client == NULL) return;
  2306. +
  2307. + if (g_userscripts_loader_observer == NULL) {
  2308. + g_userscripts_loader_observer = new CallbackObserver();
  2309. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  2310. + }
  2311. +}
  2312. +
  2313. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  2314. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  2315. +}
  2316. +
  2317. +static void OnUserScriptLoaded(JNIEnv* env,
  2318. + bool result, const std::string& error) {
  2319. + base::android::ScopedJavaLocalRef<jstring> j_error =
  2320. + base::android::ConvertUTF8ToJavaString(env, error);
  2321. +
  2322. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  2323. +}
  2324. +
  2325. +}
  2326. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  2327. new file mode 100644
  2328. --- /dev/null
  2329. +++ b/components/user_scripts/android/user_scripts_bridge.h
  2330. @@ -0,0 +1,31 @@
  2331. +/*
  2332. + This file is part of Bromite.
  2333. +
  2334. + Bromite is free software: you can redistribute it and/or modify
  2335. + it under the terms of the GNU General Public License as published by
  2336. + the Free Software Foundation, either version 3 of the License, or
  2337. + (at your option) any later version.
  2338. +
  2339. + Bromite is distributed in the hope that it will be useful,
  2340. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2341. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2342. + GNU General Public License for more details.
  2343. +
  2344. + You should have received a copy of the GNU General Public License
  2345. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2346. +*/
  2347. +
  2348. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2349. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2350. +
  2351. +#include <jni.h>
  2352. +
  2353. +namespace user_scripts {
  2354. +
  2355. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  2356. +static void OnUserScriptLoaded(JNIEnv* env,
  2357. + bool result, const std::string& error);
  2358. +
  2359. +} // namespace user_scripts
  2360. +
  2361. +#endif
  2362. \ No newline at end of file
  2363. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  2364. new file mode 100755
  2365. --- /dev/null
  2366. +++ b/components/user_scripts/browser/BUILD.gn
  2367. @@ -0,0 +1,82 @@
  2368. +# This file is part of Bromite.
  2369. +
  2370. +# Bromite is free software: you can redistribute it and/or modify
  2371. +# it under the terms of the GNU General Public License as published by
  2372. +# the Free Software Foundation, either version 3 of the License, or
  2373. +# (at your option) any later version.
  2374. +
  2375. +# Bromite is distributed in the hope that it will be useful,
  2376. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2377. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2378. +# GNU General Public License for more details.
  2379. +
  2380. +# You should have received a copy of the GNU General Public License
  2381. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2382. +
  2383. +import("//build/config/features.gni")
  2384. +import("//tools/grit/grit_rule.gni")
  2385. +
  2386. +group("browser") {
  2387. + public_deps = [
  2388. + "//components/user_scripts/browser:browser_sources",
  2389. + ]
  2390. +}
  2391. +
  2392. +source_set("browser_sources") {
  2393. + visibility = [ "./*" ]
  2394. +
  2395. + sources = [
  2396. + "file_task_runner.cc",
  2397. + "file_task_runner.h",
  2398. + "userscripts_browser_client.cc",
  2399. + "userscripts_browser_client.h",
  2400. + "user_script_loader.cc",
  2401. + "user_script_loader.h",
  2402. + "user_script_prefs.cc",
  2403. + "user_script_prefs.h",
  2404. + "user_script_pref_info.cc",
  2405. + "user_script_pref_info.h",
  2406. + "ui/user_scripts_ui.h",
  2407. + "ui/user_scripts_ui.cc",
  2408. + ]
  2409. +
  2410. + deps = [
  2411. + ":userscripts_browser_resources",
  2412. + "//base:i18n",
  2413. + "//components/keyed_service/content",
  2414. + "//components/keyed_service/core",
  2415. + "//components/pref_registry",
  2416. + "//components/prefs",
  2417. + "//content/public/browser",
  2418. + "//crypto:platform",
  2419. + "//components/user_scripts/common",
  2420. + "//services/device/public/mojom",
  2421. + "//services/preferences/public/cpp",
  2422. + "//services/service_manager/public/cpp",
  2423. + "//third_party/blink/public/common",
  2424. + "//ui/display",
  2425. + ]
  2426. +
  2427. + public_deps = [
  2428. + "//content/public/common",
  2429. + ]
  2430. +
  2431. + configs += [
  2432. + "//build/config:precompiled_headers",
  2433. + "//build/config/compiler:wexit_time_destructors",
  2434. + ]
  2435. +}
  2436. +
  2437. +group("closure_compile") {
  2438. + deps = [ "resources/user-script-ui:closure_compile" ]
  2439. +}
  2440. +
  2441. +grit("userscripts_browser_resources") {
  2442. + source = "resources/browser_resources.grd"
  2443. +
  2444. + output_dir = "$root_gen_dir/chrome"
  2445. + outputs = [
  2446. + "grit/userscripts_browser_resources.h",
  2447. + "userscripts_browser_resources.pak",
  2448. + ]
  2449. +}
  2450. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2451. new file mode 100755
  2452. --- /dev/null
  2453. +++ b/components/user_scripts/browser/file_task_runner.cc
  2454. @@ -0,0 +1,40 @@
  2455. +/*
  2456. + This file is part of Bromite.
  2457. +
  2458. + Bromite is free software: you can redistribute it and/or modify
  2459. + it under the terms of the GNU General Public License as published by
  2460. + the Free Software Foundation, either version 3 of the License, or
  2461. + (at your option) any later version.
  2462. +
  2463. + Bromite is distributed in the hope that it will be useful,
  2464. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2465. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2466. + GNU General Public License for more details.
  2467. +
  2468. + You should have received a copy of the GNU General Public License
  2469. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2470. +*/
  2471. +
  2472. +#include "file_task_runner.h"
  2473. +
  2474. +#include "base/task/sequenced_task_runner.h"
  2475. +#include "base/task/lazy_thread_pool_task_runner.h"
  2476. +#include "base/task/task_traits.h"
  2477. +
  2478. +namespace user_scripts {
  2479. +
  2480. +namespace {
  2481. +
  2482. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2483. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2484. + base::TaskTraits(base::MayBlock(),
  2485. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2486. + base::TaskPriority::USER_VISIBLE));
  2487. +
  2488. +} // namespace
  2489. +
  2490. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2491. + return g_us_task_runner.Get();
  2492. +}
  2493. +
  2494. +} // namespace user_scripts
  2495. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2496. new file mode 100755
  2497. --- /dev/null
  2498. +++ b/components/user_scripts/browser/file_task_runner.h
  2499. @@ -0,0 +1,34 @@
  2500. +/*
  2501. + This file is part of Bromite.
  2502. +
  2503. + Bromite is free software: you can redistribute it and/or modify
  2504. + it under the terms of the GNU General Public License as published by
  2505. + the Free Software Foundation, either version 3 of the License, or
  2506. + (at your option) any later version.
  2507. +
  2508. + Bromite is distributed in the hope that it will be useful,
  2509. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2510. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2511. + GNU General Public License for more details.
  2512. +
  2513. + You should have received a copy of the GNU General Public License
  2514. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2515. +*/
  2516. +
  2517. +#ifndef USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2518. +#define USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2519. +
  2520. +#include "base/memory/ref_counted.h"
  2521. +#include "base/task/task_traits.h"
  2522. +
  2523. +namespace base {
  2524. +class SequencedTaskRunner;
  2525. +}
  2526. +
  2527. +namespace user_scripts {
  2528. +
  2529. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2530. +
  2531. +} // namespace extensions
  2532. +
  2533. +#endif // USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2534. diff --git a/components/user_scripts/browser/resources/browser_resources.grd b/components/user_scripts/browser/resources/browser_resources.grd
  2535. new file mode 100644
  2536. --- /dev/null
  2537. +++ b/components/user_scripts/browser/resources/browser_resources.grd
  2538. @@ -0,0 +1,14 @@
  2539. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  2540. + <outputs>
  2541. + <output filename="grit/userscripts_browser_resources.h" type="rc_header">
  2542. + <emit emit_type='prepend'></emit>
  2543. + </output>
  2544. + <output filename="userscripts_browser_resources.pak" type="data_package" />
  2545. + </outputs>
  2546. + <release seq="1">
  2547. + <includes>
  2548. + <include name="IDR_USER_SCRIPTS_HTML" file="user-script-ui\user-scripts-ui.html" type="BINDATA" />
  2549. + <include name="IDR_USER_SCRIPTS_JS" file="user-script-ui\user-scripts-ui.js" type="BINDATA" />
  2550. + </includes>
  2551. + </release>
  2552. +</grit>
  2553. \ No newline at end of file
  2554. diff --git a/components/user_scripts/browser/resources/user-script-ui/BUILD.gn b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2555. new file mode 100644
  2556. --- /dev/null
  2557. +++ b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2558. @@ -0,0 +1,12 @@
  2559. +import("//third_party/closure_compiler/compile_js.gni")
  2560. +
  2561. +js_type_check("closure_compile") {
  2562. + deps = [ ":view_script_source" ]
  2563. +}
  2564. +
  2565. +js_library("view_script_source") {
  2566. + deps = [
  2567. + "//ui/webui/resources/js:cr.m",
  2568. + "//ui/webui/resources/js:util.m",
  2569. + ]
  2570. +}
  2571. \ No newline at end of file
  2572. 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
  2573. new file mode 100644
  2574. --- /dev/null
  2575. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2576. @@ -0,0 +1,14 @@
  2577. +<!doctype html>
  2578. +<html lang="en">
  2579. +<head>
  2580. + <meta charset="utf-8">
  2581. + <title>Local State Debug Page</title>
  2582. + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  2583. + <script type="module" src="user-scripts-ui.js"></script>
  2584. +</head>
  2585. +<body>
  2586. + <pre id="content">
  2587. + Loading Script Source file...
  2588. + </pre>
  2589. +</body>
  2590. +</html>
  2591. \ No newline at end of file
  2592. 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
  2593. new file mode 100644
  2594. --- /dev/null
  2595. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2596. @@ -0,0 +1,9 @@
  2597. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
  2598. +import {$} from 'chrome://resources/js/util.m.js';
  2599. +
  2600. +document.addEventListener('DOMContentLoaded', function() {
  2601. + const urlParams = new URLSearchParams(window.location.search);
  2602. + sendWithPromise('requestSource', urlParams.get('key')).then(textContent => {
  2603. + $('content').textContent = textContent[0].content;
  2604. + });
  2605. +});
  2606. \ No newline at end of file
  2607. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.cc b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2608. new file mode 100644
  2609. --- /dev/null
  2610. +++ b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2611. @@ -0,0 +1,147 @@
  2612. +/*
  2613. + This file is part of Bromite.
  2614. +
  2615. + Bromite is free software: you can redistribute it and/or modify
  2616. + it under the terms of the GNU General Public License as published by
  2617. + the Free Software Foundation, either version 3 of the License, or
  2618. + (at your option) any later version.
  2619. +
  2620. + Bromite is distributed in the hope that it will be useful,
  2621. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2622. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2623. + GNU General Public License for more details.
  2624. +
  2625. + You should have received a copy of the GNU General Public License
  2626. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2627. +*/
  2628. +
  2629. +
  2630. +#include <memory>
  2631. +
  2632. +#include "base/bind.h"
  2633. +#include "base/json/json_string_value_serializer.h"
  2634. +#include "base/memory/writable_shared_memory_region.h"
  2635. +#include "base/strings/string_util.h"
  2636. +#include "base/values.h"
  2637. +
  2638. +#include "chrome/browser/browser_process.h"
  2639. +#include "chrome/browser/profiles/profile.h"
  2640. +#include "chrome/common/url_constants.h"
  2641. +#include "chrome/grit/userscripts_browser_resources.h"
  2642. +#include "components/prefs/pref_service.h"
  2643. +#include "content/public/browser/web_ui.h"
  2644. +#include "content/public/browser/web_ui_controller.h"
  2645. +#include "content/public/browser/web_ui_data_source.h"
  2646. +#include "content/public/browser/web_ui_message_handler.h"
  2647. +
  2648. +#include "user_scripts_ui.h"
  2649. +#include "../userscripts_browser_client.h"
  2650. +#include "../../common/user_script.h"
  2651. +
  2652. +namespace {
  2653. +
  2654. +class UserScriptsUIHandler : public content::WebUIMessageHandler {
  2655. + public:
  2656. + UserScriptsUIHandler(const UserScriptsUIHandler&) = delete;
  2657. + UserScriptsUIHandler& operator=(const UserScriptsUIHandler&) = delete;
  2658. + UserScriptsUIHandler();
  2659. + ~UserScriptsUIHandler() override;
  2660. +
  2661. + // content::WebUIMessageHandler:
  2662. + void RegisterMessages() override;
  2663. +
  2664. + private:
  2665. + void HandleRequestSource(const base::Value::List& args);
  2666. + void OnScriptsLoaded(
  2667. + const std::string callback_id,
  2668. + const std::string script_key,
  2669. + std::unique_ptr<user_scripts::UserScriptList> user_scripts);
  2670. +
  2671. + std::unique_ptr<user_scripts::UserScriptList> loaded_scripts_;
  2672. +
  2673. + base::WeakPtrFactory<UserScriptsUIHandler> weak_factory_{this};
  2674. +};
  2675. +
  2676. +UserScriptsUIHandler::UserScriptsUIHandler()
  2677. + : loaded_scripts_(new user_scripts::UserScriptList()) {
  2678. +}
  2679. +
  2680. +UserScriptsUIHandler::~UserScriptsUIHandler() {
  2681. +}
  2682. +
  2683. +void UserScriptsUIHandler::RegisterMessages() {
  2684. + web_ui()->RegisterMessageCallback(
  2685. + "requestSource",
  2686. + base::BindRepeating(&UserScriptsUIHandler::HandleRequestSource,
  2687. + base::Unretained(this)));
  2688. +}
  2689. +
  2690. +void UserScriptsUIHandler::HandleRequestSource(const base::Value::List& args) {
  2691. + AllowJavascript();
  2692. + if (args.size() < 2) return;
  2693. +
  2694. + std::string callback_id = args[0].GetString();
  2695. + std::string script_key = args[1].GetString();
  2696. + if (script_key.empty()) {
  2697. + std::string json = "Missing key value.";
  2698. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2699. + return;
  2700. + }
  2701. +
  2702. + user_scripts::UserScriptsBrowserClient* client = user_scripts::UserScriptsBrowserClient::GetInstance();
  2703. + if (client == NULL) {
  2704. + std::string json = "User scripts disabled.";
  2705. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2706. + } else {
  2707. + std::unique_ptr<user_scripts::UserScriptList> scripts_to_load =
  2708. + std::move(loaded_scripts_);
  2709. + scripts_to_load->clear();
  2710. +
  2711. + client->GetLoader()->LoadScripts(std::move(scripts_to_load),
  2712. + base::BindOnce(
  2713. + &UserScriptsUIHandler::OnScriptsLoaded,
  2714. + weak_factory_.GetWeakPtr(),
  2715. + callback_id, script_key)
  2716. + );
  2717. + }
  2718. +}
  2719. +
  2720. +void UserScriptsUIHandler::OnScriptsLoaded(
  2721. + const std::string callback_id,
  2722. + const std::string script_key,
  2723. + std::unique_ptr<user_scripts::UserScriptList> user_scripts) {
  2724. + loaded_scripts_ = std::move(user_scripts);
  2725. +
  2726. + base::ListValue response;
  2727. + for (const std::unique_ptr<user_scripts::UserScript>& script : *loaded_scripts_) {
  2728. + if (script->key() == script_key) {
  2729. + auto scriptData = std::make_unique<base::DictionaryValue>();
  2730. + for (const std::unique_ptr<user_scripts::UserScript::File>& js_file :
  2731. + script->js_scripts()) {
  2732. + base::StringPiece contents = js_file->GetContent();
  2733. + scriptData->SetString("content", contents.data());
  2734. + }
  2735. + response.Append(std::move(scriptData));
  2736. + }
  2737. + }
  2738. +
  2739. + ResolveJavascriptCallback(base::Value(callback_id), response);
  2740. +}
  2741. +
  2742. +} // namespace
  2743. +
  2744. +namespace user_scripts {
  2745. +
  2746. +UserScriptsUI::UserScriptsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  2747. + content::WebUIDataSource* html_source =
  2748. + content::WebUIDataSource::Create(kChromeUIUserScriptsHost);
  2749. + html_source->SetDefaultResource(IDR_USER_SCRIPTS_HTML);
  2750. + html_source->AddResourcePath("user-scripts-ui.js", IDR_USER_SCRIPTS_JS);
  2751. + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
  2752. + web_ui->AddMessageHandler(std::make_unique<UserScriptsUIHandler>());
  2753. +}
  2754. +
  2755. +UserScriptsUI::~UserScriptsUI() {
  2756. +}
  2757. +
  2758. +}
  2759. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.h b/components/user_scripts/browser/ui/user_scripts_ui.h
  2760. new file mode 100644
  2761. --- /dev/null
  2762. +++ b/components/user_scripts/browser/ui/user_scripts_ui.h
  2763. @@ -0,0 +1,37 @@
  2764. +/*
  2765. + This file is part of Bromite.
  2766. +
  2767. + Bromite is free software: you can redistribute it and/or modify
  2768. + it under the terms of the GNU General Public License as published by
  2769. + the Free Software Foundation, either version 3 of the License, or
  2770. + (at your option) any later version.
  2771. +
  2772. + Bromite is distributed in the hope that it will be useful,
  2773. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2774. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2775. + GNU General Public License for more details.
  2776. +
  2777. + You should have received a copy of the GNU General Public License
  2778. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2779. +*/
  2780. +
  2781. +#ifndef USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2782. +#define USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2783. +
  2784. +#include "content/public/browser/web_ui_controller.h"
  2785. +
  2786. +namespace user_scripts {
  2787. +
  2788. +const char kChromeUIUserScriptsHost[] = "user-scripts";
  2789. +
  2790. +class UserScriptsUI : public content::WebUIController {
  2791. + public:
  2792. + UserScriptsUI(const UserScriptsUI&) = delete;
  2793. + UserScriptsUI& operator=(const UserScriptsUI&) = delete;
  2794. + explicit UserScriptsUI(content::WebUI* web_ui);
  2795. + ~UserScriptsUI() override;
  2796. +};
  2797. +
  2798. +}
  2799. +
  2800. +#endif
  2801. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2802. new file mode 100755
  2803. --- /dev/null
  2804. +++ b/components/user_scripts/browser/user_script_loader.cc
  2805. @@ -0,0 +1,716 @@
  2806. +/*
  2807. + This file is part of Bromite.
  2808. +
  2809. + Bromite is free software: you can redistribute it and/or modify
  2810. + it under the terms of the GNU General Public License as published by
  2811. + the Free Software Foundation, either version 3 of the License, or
  2812. + (at your option) any later version.
  2813. +
  2814. + Bromite is distributed in the hope that it will be useful,
  2815. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2816. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2817. + GNU General Public License for more details.
  2818. +
  2819. + You should have received a copy of the GNU General Public License
  2820. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2821. +*/
  2822. +
  2823. +#include "user_script_loader.h"
  2824. +
  2825. +#include <stddef.h>
  2826. +
  2827. +#include <set>
  2828. +#include <string>
  2829. +#include <utility>
  2830. +
  2831. +#include "base/bind.h"
  2832. +#include "base/memory/writable_shared_memory_region.h"
  2833. +#include "base/strings/string_util.h"
  2834. +#include "base/strings/strcat.h"
  2835. +#include "base/files/file.h"
  2836. +#include "base/files/file_util.h"
  2837. +#include "base/files/file_enumerator.h"
  2838. +#include "base/i18n/file_util_icu.h"
  2839. +#include "base/path_service.h"
  2840. +#include "base/base_paths_android.h"
  2841. +#include "base/strings/utf_string_conversions.h"
  2842. +#include "base/android/content_uri_utils.h"
  2843. +#include "base/android/jni_android.h"
  2844. +#include "base/task/task_traits.h"
  2845. +#include "base/version.h"
  2846. +
  2847. +#include "crypto/sha2.h"
  2848. +#include "base/base64.h"
  2849. +
  2850. +#include "build/build_config.h"
  2851. +#include "content/public/browser/browser_context.h"
  2852. +#include "content/public/browser/browser_task_traits.h"
  2853. +#include "content/public/browser/browser_thread.h"
  2854. +#include "content/public/browser/notification_service.h"
  2855. +#include "content/public/browser/notification_types.h"
  2856. +#include "content/public/browser/render_process_host.h"
  2857. +#include "ui/shell_dialogs/select_file_dialog.h"
  2858. +#include "content/browser/file_system_access/file_system_chooser.h"
  2859. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2860. +#include "ui/android/window_android.h"
  2861. +
  2862. +#include "../common/user_scripts_features.h"
  2863. +#include "../common/extension_messages.h"
  2864. +#include "file_task_runner.h"
  2865. +#include "user_script_prefs.h"
  2866. +#include "user_script_pref_info.h"
  2867. +#include "../common/host_id.h"
  2868. +
  2869. +using content::BrowserThread;
  2870. +using content::BrowserContext;
  2871. +
  2872. +namespace user_scripts {
  2873. +
  2874. +namespace {
  2875. +
  2876. +static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2877. +static const base::StringPiece kUserScriptEnd("// ==/UserScript==");
  2878. +static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2879. +static const base::StringPiece kNameDeclaration("// @name");
  2880. +static const base::StringPiece kVersionDeclaration("// @version");
  2881. +static const base::StringPiece kDescriptionDeclaration("// @description");
  2882. +static const base::StringPiece kIncludeDeclaration("// @include");
  2883. +static const base::StringPiece kExcludeDeclaration("// @exclude");
  2884. +static const base::StringPiece kMatchDeclaration("// @match");
  2885. +static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2886. +static const base::StringPiece kRunAtDeclaration("// @run-at");
  2887. +static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2888. +static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2889. +static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2890. +static const base::StringPiece kUrlSourceDeclaration("// @url");
  2891. +static const base::StringPiece kUrlHomePageDeclaration("// @homepage");
  2892. +
  2893. +// internal use
  2894. +static const base::StringPiece kParserError("// @error");
  2895. +static const base::StringPiece kForceDisabled("// @disabled");
  2896. +
  2897. +// Helper function to parse greasesmonkey headers
  2898. +bool GetDeclarationValue(const base::StringPiece& line,
  2899. + const base::StringPiece& prefix,
  2900. + std::string* value) {
  2901. + base::StringPiece::size_type index = line.find(prefix);
  2902. + if (index == base::StringPiece::npos)
  2903. + return false;
  2904. +
  2905. + std::string temp(line.data() + index + prefix.length(),
  2906. + line.length() - index - prefix.length());
  2907. +
  2908. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2909. + return false;
  2910. +
  2911. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2912. + return true;
  2913. +}
  2914. +
  2915. +} // namespace
  2916. +
  2917. +// static
  2918. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2919. + std::unique_ptr<UserScript>& script,
  2920. + bool *found_metadata,
  2921. + std::string& error_message) {
  2922. + // http://wiki.greasespot.net/Metadata_block
  2923. + base::StringPiece line;
  2924. + size_t line_start = 0;
  2925. + size_t line_end = line_start;
  2926. + *found_metadata = false;
  2927. +
  2928. + while (line_start < script_text.length()) {
  2929. + line_end = script_text.find('\n', line_start);
  2930. +
  2931. + // Handle the case where there is no trailing newline in the file.
  2932. + if (line_end == std::string::npos)
  2933. + line_end = script_text.length() - 1;
  2934. +
  2935. + line = base::StringPiece(script_text.data() + line_start,
  2936. + line_end - line_start);
  2937. +
  2938. + if (!*found_metadata) {
  2939. + if (base::StartsWith(line, kUserScriptBegin))
  2940. + *found_metadata = true;
  2941. + } else {
  2942. + if (base::StartsWith(line, kUserScriptEnd))
  2943. + break;
  2944. +
  2945. + std::string value;
  2946. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2947. + // We escape some characters that MatchPattern() considers special.
  2948. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2949. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2950. + script->add_glob(value);
  2951. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2952. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2953. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2954. + script->add_exclude_glob(value);
  2955. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2956. + script->set_name_space(value);
  2957. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2958. + script->set_name(value);
  2959. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2960. + base::Version version(value);
  2961. + if (version.IsValid())
  2962. + script->set_version(version.GetString());
  2963. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  2964. + script->set_description(value);
  2965. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  2966. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  2967. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  2968. + error_message = "Invalid UserScript Schema " + value;
  2969. + return false;
  2970. + }
  2971. + script->add_url_pattern(pattern);
  2972. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  2973. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  2974. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  2975. + error_message = "Invalid UserScript Schema " + value;
  2976. + return false;
  2977. + }
  2978. + script->add_exclude_url_pattern(exclude);
  2979. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  2980. + if (value == kRunAtDocumentStartValue)
  2981. + script->set_run_location(UserScript::DOCUMENT_START);
  2982. + else if (value == kRunAtDocumentEndValue)
  2983. + script->set_run_location(UserScript::DOCUMENT_END);
  2984. + else if (value == kRunAtDocumentIdleValue)
  2985. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  2986. + else {
  2987. + error_message = "Invalid RunAtDeclaration " + value;
  2988. + return false;
  2989. + }
  2990. + } else if (GetDeclarationValue(line, kUrlSourceDeclaration, &value) ||
  2991. + GetDeclarationValue(line, kUrlHomePageDeclaration, &value)) {
  2992. + script->set_url_source(value);
  2993. + } else if (GetDeclarationValue(line, kParserError, &value)) {
  2994. + script->set_parser_error(value);
  2995. + } else if (GetDeclarationValue(line, kForceDisabled, &value)) {
  2996. + script->set_force_disabled();
  2997. + }
  2998. +
  2999. + // TODO(aa): Handle more types of metadata.
  3000. + }
  3001. +
  3002. + line_start = line_end + 1;
  3003. + }
  3004. +
  3005. + // If no patterns were specified, default to @include *. This is what
  3006. + // Greasemonkey does.
  3007. + if (script->globs().empty() && script->url_patterns().is_empty())
  3008. + script->add_glob("*");
  3009. +
  3010. + return true;
  3011. +}
  3012. +
  3013. +// static
  3014. +bool LoadUserScriptFromFile(
  3015. + const base::FilePath& user_script_path, const GURL& original_url,
  3016. + std::unique_ptr<UserScript>& script,
  3017. + bool* found_metadata,
  3018. + std::u16string* error) {
  3019. +
  3020. + base::File infile;
  3021. + if (user_script_path.IsContentUri()) {
  3022. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3023. + LOG(INFO) << "UserScriptLoader: path " << user_script_path << " is a content uri";
  3024. +
  3025. + infile = OpenContentUriForRead(user_script_path);
  3026. + } else {
  3027. + infile = base::File(user_script_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  3028. + }
  3029. +
  3030. + if (!infile.IsValid()) {
  3031. + base::File::Error out_error = infile.error_details();
  3032. + *error = u"Cannot open script source. Error: " +
  3033. + base::ASCIIToUTF16(base::File::ErrorToString(out_error));
  3034. + return false;
  3035. + }
  3036. +
  3037. + auto length = infile.GetLength();
  3038. + if (length<=0) {
  3039. + *error = u"File is empty.";
  3040. + return false;
  3041. + }
  3042. +
  3043. + auto buffer = std::vector<char>(length);
  3044. + int bytes_read = infile.Read(0, buffer.data(), length);
  3045. + if (bytes_read == -1) {
  3046. + *error = u"Could not read source file.";
  3047. + return false;
  3048. + }
  3049. +
  3050. + std::string content(buffer.begin(), buffer.end());
  3051. + if (!base::IsStringUTF8(content)) {
  3052. + *error = u"User script must be UTF8 encoded.";
  3053. + return false;
  3054. + }
  3055. +
  3056. + std::string detailed_error;
  3057. + bool parseResult = UserScriptLoader::ParseMetadataHeader(content, script,
  3058. + found_metadata, detailed_error);
  3059. + if (parseResult == false || *found_metadata == false) {
  3060. + std::u16string detailed_error16;
  3061. + base::UTF8ToUTF16(detailed_error.c_str(), detailed_error.length(), &detailed_error16);
  3062. + *error = base::StrCat({u"Invalid script header. ", detailed_error16});
  3063. + return false;
  3064. + }
  3065. +
  3066. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  3067. +
  3068. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  3069. + file->set_content(content);
  3070. +
  3071. + // create SHA256 of file
  3072. + char raw[crypto::kSHA256Length] = {0};
  3073. + std::string key;
  3074. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  3075. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  3076. + file->set_key(key);
  3077. +
  3078. + file->set_url(GURL(base::StrCat({"https://userscripts/file/", key, ".js"})));
  3079. +
  3080. + script->js_scripts().push_back(std::move(file));
  3081. +
  3082. + // add into key the filename
  3083. + // this value is used in ui to discriminate scripts
  3084. + script->set_key(user_script_path.BaseName().value());
  3085. + return true;
  3086. +}
  3087. +
  3088. +// static
  3089. +bool GetOrCreatePath(base::FilePath& path) {
  3090. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  3091. + path = path.AppendASCII("userscripts");
  3092. +
  3093. + // create snippets directory if not exists
  3094. + if (!base::PathExists(path)) {
  3095. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  3096. + base::File::Error error = base::File::FILE_OK;
  3097. + if (!base::CreateDirectoryAndGetError(path, &error)) {
  3098. + LOG(ERROR) <<
  3099. + "UserScriptLoader: failed to create directory: " << path
  3100. + << " with error code " << error;
  3101. + return false;
  3102. + }
  3103. + }
  3104. + return true;
  3105. +}
  3106. +
  3107. +// static
  3108. +void LoadUserScripts(UserScriptList* user_scripts_list) {
  3109. + base::FilePath path;
  3110. + if (GetOrCreatePath(path) == false) return;
  3111. +
  3112. + // enumerate all files from script path
  3113. + // we accept all files, but we check if it's a real
  3114. + // userscript
  3115. + base::FileEnumerator dir_enum(
  3116. + path,
  3117. + /*recursive=*/false, base::FileEnumerator::FILES);
  3118. + base::FilePath full_name;
  3119. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  3120. + std::unique_ptr<UserScript> userscript(new UserScript());
  3121. + userscript->set_id(UserScript::GenerateUserScriptID());
  3122. + userscript->set_host_id(HostID(HostID::HostType::EXTENSIONS,
  3123. + "_" + base::NumberToString(userscript->id())));
  3124. +
  3125. + std::u16string error;
  3126. + bool found_metadata;
  3127. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &found_metadata, &error)) {
  3128. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3129. + LOG(INFO) << "UserScriptLoader: Found user script " << userscript->name() <<
  3130. + "-" << userscript->version() <<
  3131. + "-" << userscript->description();
  3132. +
  3133. + userscript->set_file_path(full_name.AsUTF8Unsafe());
  3134. + user_scripts_list->push_back(std::move(userscript));
  3135. + } else {
  3136. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3137. + }
  3138. + }
  3139. +}
  3140. +
  3141. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  3142. + UserScriptsPrefs* prefs)
  3143. + : loaded_scripts_(new UserScriptList()),
  3144. + ready_(false),
  3145. + browser_context_(browser_context),
  3146. + prefs_(prefs) {}
  3147. +
  3148. +UserScriptLoader::~UserScriptLoader() {
  3149. + for (auto& observer : observers_)
  3150. + observer.OnUserScriptLoaderDestroyed(this);
  3151. +}
  3152. +
  3153. +void UserScriptLoader::OnRenderProcessHostCreated(
  3154. + content::RenderProcessHost* process_host) {
  3155. + if (initial_load_complete()) {
  3156. + SendUpdate(process_host, shared_memory_);
  3157. + }
  3158. +}
  3159. +
  3160. +void UserScriptLoader::SetReady(bool ready) {
  3161. + bool was_ready = ready_;
  3162. + ready_ = ready;
  3163. + if (ready_ && !was_ready)
  3164. + AttemptLoad();
  3165. +}
  3166. +
  3167. +void UserScriptLoader::AttemptLoad() {
  3168. + int tryOut = prefs_->GetCurrentStartupTryout();
  3169. + if (tryOut >= 3) {
  3170. + LOG(INFO) << "UserScriptLoader: Possible crash detected. UserScript disabled";
  3171. + prefs_->SetEnabled(false);
  3172. + } else {
  3173. + prefs_->StartupTryout(tryOut+1);
  3174. + StartLoad();
  3175. + }
  3176. +}
  3177. +
  3178. +void UserScriptLoader::StartLoad() {
  3179. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3180. +
  3181. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3182. + LOG(INFO) << "UserScriptLoader: StartLoad";
  3183. +
  3184. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  3185. + // the scripts aren't currently ready.
  3186. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  3187. + scripts_to_load->clear();
  3188. +
  3189. + if (prefs_->IsEnabled()) {
  3190. + LoadScripts(std::move(scripts_to_load),
  3191. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  3192. + weak_factory_.GetWeakPtr()));
  3193. + } else {
  3194. + OnScriptsLoaded(std::move(scripts_to_load));
  3195. + }
  3196. +}
  3197. +
  3198. +// static
  3199. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  3200. + const UserScriptList& scripts) {
  3201. + base::Pickle pickle;
  3202. + pickle.WriteUInt32(scripts.size());
  3203. + for (const std::unique_ptr<UserScript>& script : scripts) {
  3204. + // TODO(aa): This can be replaced by sending content script metadata to
  3205. + // renderers along with other extension data in ExtensionMsg_Loaded.
  3206. + // See crbug.com/70516.
  3207. + script->Pickle(&pickle);
  3208. + // Write scripts as 'data' so that we can read it out in the slave without
  3209. + // allocating a new string.
  3210. + for (const std::unique_ptr<UserScript::File>& js_file :
  3211. + script->js_scripts()) {
  3212. + base::StringPiece contents = js_file->GetContent();
  3213. + pickle.WriteData(contents.data(), contents.length());
  3214. + }
  3215. + for (const std::unique_ptr<UserScript::File>& css_file :
  3216. + script->css_scripts()) {
  3217. + base::StringPiece contents = css_file->GetContent();
  3218. + pickle.WriteData(contents.data(), contents.length());
  3219. + }
  3220. + }
  3221. +
  3222. + // Create the shared memory object.
  3223. + base::MappedReadOnlyRegion shared_memory =
  3224. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  3225. + if (!shared_memory.IsValid())
  3226. + return {};
  3227. +
  3228. + // Copy the pickle to shared memory.
  3229. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  3230. + return std::move(shared_memory.region);
  3231. +}
  3232. +
  3233. +void UserScriptLoader::AddObserver(Observer* observer) {
  3234. + observers_.AddObserver(observer);
  3235. +}
  3236. +
  3237. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  3238. + observers_.RemoveObserver(observer);
  3239. +}
  3240. +
  3241. +void UserScriptLoader::OnScriptsLoaded(
  3242. + std::unique_ptr<UserScriptList> user_scripts) {
  3243. +
  3244. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3245. + LOG(INFO) << "UserScriptLoader: OnScriptsLoaded";
  3246. +
  3247. + // Check user preferences for loaded user scripts
  3248. + prefs_->CompareWithPrefs(*user_scripts);
  3249. + loaded_scripts_ = std::move(user_scripts);
  3250. +
  3251. + base::ReadOnlySharedMemoryRegion shared_memory;
  3252. + shared_memory =
  3253. + UserScriptLoader::Serialize(*loaded_scripts_);
  3254. +
  3255. + if (!shared_memory.IsValid()) {
  3256. + // This can happen if we run out of file descriptors. In that case, we
  3257. + // have a choice between silently omitting all user scripts for new tabs,
  3258. + // by nulling out shared_memory_, or only silently omitting new ones by
  3259. + // leaving the existing object in place. The second seems less bad, even
  3260. + // though it removes the possibility that freeing the shared memory block
  3261. + // would open up enough FDs for long enough for a retry to succeed.
  3262. +
  3263. + // Pretend the extension change didn't happen.
  3264. + return;
  3265. + }
  3266. +
  3267. + // We've got scripts ready to go.
  3268. + shared_memory_ = std::move(shared_memory);
  3269. +
  3270. + for (content::RenderProcessHost::iterator i(
  3271. + content::RenderProcessHost::AllHostsIterator());
  3272. + !i.IsAtEnd(); i.Advance()) {
  3273. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  3274. + }
  3275. +
  3276. + // DCHECK(false); trying crash
  3277. + prefs_->StartupTryout(0);
  3278. +
  3279. + for (auto& observer : observers_)
  3280. + observer.OnScriptsLoaded(this, browser_context_);
  3281. +}
  3282. +
  3283. +void UserScriptLoader::SendUpdate(
  3284. + content::RenderProcessHost* process,
  3285. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  3286. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3287. + LOG(INFO) << "UserScriptLoader: SendUpdate";
  3288. +
  3289. + // If the process is being started asynchronously, early return. We'll end up
  3290. + // calling InitUserScripts when it's created which will call this again.
  3291. + base::ProcessHandle handle = process->GetProcess().Handle();
  3292. + if (!handle)
  3293. + return;
  3294. +
  3295. + base::ReadOnlySharedMemoryRegion region_for_process =
  3296. + shared_memory.Duplicate();
  3297. + if (!region_for_process.IsValid())
  3298. + return;
  3299. +
  3300. + process->Send(new ExtensionMsg_UpdateUserScripts(
  3301. + std::move(region_for_process)));
  3302. +}
  3303. +
  3304. +void LoadScriptsOnFileTaskRunner(
  3305. + std::unique_ptr<UserScriptList> user_scripts,
  3306. + UserScriptLoader::LoadScriptsCallback callback) {
  3307. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3308. + DCHECK(user_scripts.get());
  3309. +
  3310. + // load user scripts from path
  3311. + LoadUserScripts(user_scripts.get());
  3312. +
  3313. + // Explicit priority to prevent unwanted task priority inheritance.
  3314. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3315. + ->PostTask(FROM_HERE,
  3316. + base::BindOnce(std::move(callback), std::move(user_scripts)));
  3317. +}
  3318. +
  3319. +void UserScriptLoader::LoadScripts(
  3320. + std::unique_ptr<UserScriptList> user_scripts,
  3321. + LoadScriptsCallback callback) {
  3322. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  3323. +
  3324. + GetUserScriptsFileTaskRunner()->PostTask(
  3325. + FROM_HERE,
  3326. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  3327. + std::move(callback)));
  3328. +}
  3329. +
  3330. +void RemoveScriptsOnFileTaskRunner(
  3331. + const std::string& script_id,
  3332. + UserScriptLoader::RemoveScriptCallback callback) {
  3333. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3334. +
  3335. + base::FilePath path;
  3336. + if (GetOrCreatePath(path)) {
  3337. + base::FilePath file = path.Append(script_id);
  3338. + if (base::DeleteFile(file) == false) {
  3339. + LOG(ERROR) <<
  3340. + "ERROR: failed to delete file : " << path;
  3341. + }
  3342. + }
  3343. +
  3344. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3345. + ->PostTask(FROM_HERE,
  3346. + base::BindOnce(std::move(callback)));
  3347. +}
  3348. +
  3349. +void UserScriptLoader::OnScriptRemoved() {
  3350. + StartLoad();
  3351. +}
  3352. +
  3353. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  3354. + if (!prefs_->IsEnabled()) return;
  3355. + prefs_->RemoveScriptFromPrefs(script_id);
  3356. +
  3357. + GetUserScriptsFileTaskRunner()->PostTask(
  3358. + FROM_HERE,
  3359. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  3360. + std::move(script_id),
  3361. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  3362. + weak_factory_.GetWeakPtr())));
  3363. +}
  3364. +
  3365. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3366. + if (!prefs_->IsEnabled()) return;
  3367. + prefs_->SetScriptEnabled(script_id, is_enabled);
  3368. + StartLoad();
  3369. +}
  3370. +
  3371. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  3372. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3373. +
  3374. + if (!prefs_->IsEnabled()) return;
  3375. +
  3376. + dialog_ = ui::SelectFileDialog::Create(
  3377. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  3378. +
  3379. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  3380. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  3381. + allowed_file_info.allowed_paths =
  3382. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  3383. + base::FilePath suggested_name;
  3384. +
  3385. + std::vector<std::u16string> types;
  3386. + types.push_back(u"*/*"); /*= java SelectFileDialog.ALL_TYPES*/
  3387. + std::pair<std::vector<std::u16string>, bool> accept_types = std::make_pair(
  3388. + types, false /*use_media_capture*/);
  3389. +
  3390. + dialog_->SelectFile(
  3391. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  3392. + std::u16string() /* dialog title*/, suggested_name, &allowed_file_info,
  3393. + 0 /* file type index */, std::string() /* default file extension */,
  3394. + nativeWindow,
  3395. + &accept_types /* params */);
  3396. +}
  3397. +
  3398. +
  3399. +void LoadScriptFromPathOnFileTaskRunner(
  3400. + const base::FilePath& path,
  3401. + const std::string& display_name,
  3402. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  3403. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3404. +
  3405. + std::unique_ptr<UserScript> userscript(new UserScript());
  3406. + std::u16string error;
  3407. + bool found_metadata = false;
  3408. + bool loaded = LoadUserScriptFromFile(path, GURL(), userscript, &found_metadata, &error);
  3409. +
  3410. + bool result = loaded;
  3411. + if (result || found_metadata) {
  3412. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3413. + LOG(INFO) << "UserScriptLoader: found " << userscript->name() <<
  3414. + "-" << userscript->version() <<
  3415. + "-" << userscript->description();
  3416. + base::FilePath destination;
  3417. + if (GetOrCreatePath(destination) == false) {
  3418. + error = u"Cannot create destination.";
  3419. + } else {
  3420. + // we need an unique file name
  3421. + if (display_name.empty() == false) {
  3422. + userscript->set_key(display_name);
  3423. + }
  3424. +
  3425. + // filename is original filename or display_name
  3426. + std::string file_name(userscript->key());
  3427. + base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
  3428. + destination = destination.Append(file_name);
  3429. +
  3430. + if (destination.ReferencesParent()) {
  3431. + error = u"Invalid file name.";
  3432. + result = false;
  3433. + } else if (base::PathExists(destination)) {
  3434. + error = u"User script already loaded.";
  3435. + result = false;
  3436. + } else {
  3437. + if (loaded) {
  3438. + // if is a correct userscript, copy it
  3439. + result = base::CopyFile(path, destination);
  3440. + if (result == false) {
  3441. + error = u"Copy error.";
  3442. + }
  3443. + } else {
  3444. + // else, there is a parser error
  3445. + // write minimal values and the error string, so UI can show it
  3446. + std::string combined_string = base::StrCat({
  3447. + kUserScriptBegin, "\n",
  3448. + kNamespaceDeclaration, " ", userscript->name_space(), "\n",
  3449. + kNameDeclaration, " ", userscript->name(), "\n",
  3450. + kVersionDeclaration, " ", userscript->version(), "\n",
  3451. + kDescriptionDeclaration, " ", userscript->description(), "\n",
  3452. + kUrlSourceDeclaration, " ", userscript->url_source(), "\n",
  3453. + kParserError, " ", base::UTF16ToASCII(error), "\n",
  3454. + kForceDisabled, " true\n",
  3455. + kUserScriptEnd, "\n"
  3456. + });
  3457. +
  3458. + if (!base::WriteFile(destination, combined_string)) {
  3459. + error = u"Cannot write.";
  3460. + result = false;
  3461. + }
  3462. + }
  3463. + }
  3464. + }
  3465. + }
  3466. +
  3467. + if (!error.empty()) {
  3468. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3469. + }
  3470. +
  3471. + // return to callback with eventually the error
  3472. + const std::string string_error = base::UTF16ToASCII(error);
  3473. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3474. + ->PostTask(FROM_HERE,
  3475. + base::BindOnce(std::move(callback), result,
  3476. + std::move(string_error)));
  3477. +}
  3478. +
  3479. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  3480. + if (!prefs_->IsEnabled()) return;
  3481. +
  3482. + std::u16string file_display_name;
  3483. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  3484. +
  3485. + std::string display_name = script_path.BaseName().value();
  3486. + if (base::IsStringASCII(file_display_name))
  3487. + display_name = base::UTF16ToASCII(file_display_name);
  3488. +
  3489. + GetUserScriptsFileTaskRunner()->PostTask(
  3490. + FROM_HERE,
  3491. + base::BindOnce(
  3492. + &LoadScriptFromPathOnFileTaskRunner,
  3493. + script_path, display_name,
  3494. + base::BindOnce(
  3495. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  3496. + weak_factory_.GetWeakPtr()
  3497. + )
  3498. + ));
  3499. +}
  3500. +
  3501. +void UserScriptLoader::FileSelected(
  3502. + const base::FilePath& path, int index, void* params) {
  3503. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3504. + LOG(INFO) << "UserScriptLoader: FileSelected " << path;
  3505. +
  3506. + UserScriptLoader::TryToInstall(path);
  3507. +}
  3508. +
  3509. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  3510. + bool result, const std::string& error) {
  3511. + for (auto& observer : observers_)
  3512. + observer.OnUserScriptLoaded(this, result, error);
  3513. +
  3514. + StartLoad();
  3515. +}
  3516. +
  3517. +void UserScriptLoader::FileSelectionCanceled(
  3518. + void* params) {
  3519. +}
  3520. +
  3521. +} // namespace extensions
  3522. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  3523. new file mode 100755
  3524. --- /dev/null
  3525. +++ b/components/user_scripts/browser/user_script_loader.h
  3526. @@ -0,0 +1,169 @@
  3527. +/*
  3528. + This file is part of Bromite.
  3529. +
  3530. + Bromite is free software: you can redistribute it and/or modify
  3531. + it under the terms of the GNU General Public License as published by
  3532. + the Free Software Foundation, either version 3 of the License, or
  3533. + (at your option) any later version.
  3534. +
  3535. + Bromite is distributed in the hope that it will be useful,
  3536. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3537. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3538. + GNU General Public License for more details.
  3539. +
  3540. + You should have received a copy of the GNU General Public License
  3541. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3542. +*/
  3543. +
  3544. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3545. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3546. +
  3547. +#include <map>
  3548. +#include <memory>
  3549. +#include <set>
  3550. +
  3551. +#include "base/callback_forward.h"
  3552. +#include "base/compiler_specific.h"
  3553. +#include "base/memory/read_only_shared_memory_region.h"
  3554. +#include "base/memory/weak_ptr.h"
  3555. +#include "base/observer_list.h"
  3556. +#include "content/public/browser/render_process_host_creation_observer.h"
  3557. +#include "ui/shell_dialogs/select_file_dialog.h"
  3558. +#include "content/browser/file_system_access/file_system_chooser.h"
  3559. +#include "ui/android/window_android.h"
  3560. +
  3561. +#include "../common/host_id.h"
  3562. +#include "../common/user_script.h"
  3563. +#include "user_script_prefs.h"
  3564. +
  3565. +namespace base {
  3566. +class ReadOnlySharedMemoryRegion;
  3567. +}
  3568. +
  3569. +namespace content {
  3570. +class BrowserContext;
  3571. +class RenderProcessHost;
  3572. +}
  3573. +
  3574. +namespace user_scripts {
  3575. +
  3576. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  3577. +// new shared memory region when the set of scripts changes. Also notifies
  3578. +// renderers of new shared memory region when new renderers appear, or when
  3579. +// script reloading completes. Script loading lives on the file thread.
  3580. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  3581. + public ui::SelectFileDialog::Listener {
  3582. + public:
  3583. + UserScriptLoader(const UserScriptLoader&) = delete;
  3584. + UserScriptLoader& operator=(const UserScriptLoader&) = delete;
  3585. + using LoadScriptsCallback =
  3586. + base::OnceCallback<void(std::unique_ptr<UserScriptList>)>;
  3587. + using LoadSingleScriptCallback =
  3588. + base::OnceCallback<void(bool result, const std::string& error)>;
  3589. +
  3590. + using RemoveScriptCallback =
  3591. + base::OnceCallback<void()>;
  3592. + class Observer {
  3593. + public:
  3594. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  3595. + content::BrowserContext* browser_context) = 0;
  3596. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  3597. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  3598. + bool result, const std::string& error) = 0;
  3599. + };
  3600. +
  3601. + // Parses the includes out of |script| and returns them in |includes|.
  3602. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  3603. + std::unique_ptr<UserScript>& script,
  3604. + bool *found_metadata,
  3605. + std::string& error_message);
  3606. +
  3607. + UserScriptLoader(content::BrowserContext* browser_context,
  3608. + UserScriptsPrefs* prefs);
  3609. + //const HostID& host_id);
  3610. + ~UserScriptLoader() override;
  3611. +
  3612. + // Initiates procedure to start loading scripts on the file thread.
  3613. + void StartLoad();
  3614. +
  3615. + // Returns true if we have any scripts ready.
  3616. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  3617. +
  3618. + // Pickle user scripts and return pointer to the shared memory.
  3619. + static base::ReadOnlySharedMemoryRegion Serialize(
  3620. + const user_scripts::UserScriptList& scripts);
  3621. +
  3622. + // Adds or removes observers.
  3623. + void AddObserver(Observer* observer);
  3624. + void RemoveObserver(Observer* observer);
  3625. +
  3626. + // Sets the flag if the initial set of hosts has finished loading; if it's
  3627. + // set to be true, calls AttempLoad() to bootstrap.
  3628. + void SetReady(bool ready);
  3629. +
  3630. + void RemoveScript(const std::string& script_id);
  3631. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3632. +
  3633. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  3634. + void TryToInstall(const base::FilePath& script_path);
  3635. +
  3636. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  3637. + LoadScriptsCallback callback);
  3638. +
  3639. + protected:
  3640. + content::BrowserContext* browser_context() const { return browser_context_; }
  3641. +
  3642. + UserScriptsPrefs* prefs() const { return prefs_; }
  3643. +
  3644. + private:
  3645. + void OnRenderProcessHostCreated(
  3646. + content::RenderProcessHost* process_host) override;
  3647. +
  3648. + // Attempts to initiate a load.
  3649. + void AttemptLoad();
  3650. +
  3651. + // Called once we have finished loading the scripts on the file thread.
  3652. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts);
  3653. +
  3654. + // Sends the renderer process a new set of user scripts. If
  3655. + // |changed_hosts| is not empty, this signals that only the scripts from
  3656. + // those hosts should be updated. Otherwise, all hosts will be
  3657. + // updated.
  3658. + void SendUpdate(content::RenderProcessHost* process,
  3659. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  3660. +
  3661. + // Contains the scripts that were found the last time scripts were updated.
  3662. + base::ReadOnlySharedMemoryRegion shared_memory_;
  3663. +
  3664. + // List of scripts that are currently loaded. This is null when a load is in
  3665. + // progress.
  3666. + std::unique_ptr<UserScriptList> loaded_scripts_;
  3667. +
  3668. + // If the initial set of hosts has finished loading.
  3669. + bool ready_;
  3670. +
  3671. + // The browser_context for which the scripts managed here are installed.
  3672. + content::BrowserContext* browser_context_;
  3673. +
  3674. + // Manage load and store from preferences
  3675. + UserScriptsPrefs* prefs_;
  3676. +
  3677. + // The associated observers.
  3678. + base::ObserverList<Observer>::Unchecked observers_;
  3679. +
  3680. + void OnScriptRemoved();
  3681. +
  3682. + // Manage file dialog requests
  3683. + scoped_refptr<ui::SelectFileDialog> dialog_;
  3684. + void FileSelected(const base::FilePath& path,
  3685. + int index, void* params) override;
  3686. + void FileSelectionCanceled(void* params) override;
  3687. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  3688. + bool result, const std::string& error );
  3689. +
  3690. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  3691. +};
  3692. +
  3693. +} // namespace extensions
  3694. +
  3695. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3696. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  3697. new file mode 100644
  3698. --- /dev/null
  3699. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  3700. @@ -0,0 +1,34 @@
  3701. +/*
  3702. + This file is part of Bromite.
  3703. +
  3704. + Bromite is free software: you can redistribute it and/or modify
  3705. + it under the terms of the GNU General Public License as published by
  3706. + the Free Software Foundation, either version 3 of the License, or
  3707. + (at your option) any later version.
  3708. +
  3709. + Bromite is distributed in the hope that it will be useful,
  3710. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3711. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3712. + GNU General Public License for more details.
  3713. +
  3714. + You should have received a copy of the GNU General Public License
  3715. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3716. +*/
  3717. +
  3718. +#include "user_script_pref_info.h"
  3719. +
  3720. +namespace user_scripts {
  3721. +
  3722. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  3723. + const std::string& description,
  3724. + const base::Time& install_time,
  3725. + bool enabled)
  3726. + : install_time(install_time),
  3727. + enabled(enabled),
  3728. + name_(name),
  3729. + description_(description) {}
  3730. +
  3731. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  3732. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  3733. +
  3734. +}
  3735. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3736. new file mode 100644
  3737. --- /dev/null
  3738. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3739. @@ -0,0 +1,72 @@
  3740. +/*
  3741. + This file is part of Bromite.
  3742. +
  3743. + Bromite is free software: you can redistribute it and/or modify
  3744. + it under the terms of the GNU General Public License as published by
  3745. + the Free Software Foundation, either version 3 of the License, or
  3746. + (at your option) any later version.
  3747. +
  3748. + Bromite is distributed in the hope that it will be useful,
  3749. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3750. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3751. + GNU General Public License for more details.
  3752. +
  3753. + You should have received a copy of the GNU General Public License
  3754. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3755. +*/
  3756. +
  3757. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3758. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3759. +
  3760. +#include "base/values.h"
  3761. +#include "base/time/time.h"
  3762. +#include "components/keyed_service/core/keyed_service.h"
  3763. +
  3764. +namespace user_scripts {
  3765. +
  3766. +class UserScriptsListPrefs : public KeyedService {
  3767. + public:
  3768. + struct ScriptInfo {
  3769. + ScriptInfo(const std::string& name,
  3770. + const std::string& description,
  3771. + const base::Time& install_time,
  3772. + bool enabled);
  3773. + ScriptInfo(const ScriptInfo& other);
  3774. + ~ScriptInfo();
  3775. +
  3776. + const std::string& name() const { return name_; }
  3777. + void set_name(const std::string& name) { name_ = name; }
  3778. +
  3779. + const std::string& description() const { return description_; }
  3780. + void set_description(const std::string& description) { description_ = description; }
  3781. +
  3782. + const std::string& version() const { return version_; }
  3783. + void set_version(const std::string& version) { version_ = version; }
  3784. +
  3785. + const std::string& file_path() const { return file_path_; }
  3786. + void set_file_path(const std::string& file_path) { file_path_ = file_path; }
  3787. +
  3788. + const std::string& url_source() const { return url_source_; }
  3789. + void set_url_source(const std::string& url_source) { url_source_ = url_source; }
  3790. +
  3791. + const std::string& parser_error() const { return parser_error_; }
  3792. + void set_parser_error(const std::string& parser_error) { parser_error_ = parser_error; }
  3793. +
  3794. + base::Time install_time;
  3795. + bool enabled;
  3796. +
  3797. + bool force_disabled;
  3798. +
  3799. + private:
  3800. + std::string name_;
  3801. + std::string description_;
  3802. + std::string version_;
  3803. + std::string file_path_;
  3804. + std::string url_source_;
  3805. + std::string parser_error_;
  3806. + };
  3807. +};
  3808. +
  3809. +}
  3810. +
  3811. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3812. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3813. new file mode 100644
  3814. --- /dev/null
  3815. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3816. @@ -0,0 +1,278 @@
  3817. +/*
  3818. + This file is part of Bromite.
  3819. +
  3820. + Bromite is free software: you can redistribute it and/or modify
  3821. + it under the terms of the GNU General Public License as published by
  3822. + the Free Software Foundation, either version 3 of the License, or
  3823. + (at your option) any later version.
  3824. +
  3825. + Bromite is distributed in the hope that it will be useful,
  3826. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3827. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3828. + GNU General Public License for more details.
  3829. +
  3830. + You should have received a copy of the GNU General Public License
  3831. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3832. +*/
  3833. +
  3834. +#include <map>
  3835. +
  3836. +#include "base/values.h"
  3837. +#include "base/strings/string_number_conversions.h"
  3838. +#include "base/json/json_writer.h"
  3839. +
  3840. +#include "chrome/browser/browser_process.h"
  3841. +#include "chrome/browser/profiles/profile.h"
  3842. +#include "chrome/browser/profiles/profile_manager.h"
  3843. +
  3844. +#include "components/prefs/pref_registry_simple.h"
  3845. +#include "components/prefs/pref_service.h"
  3846. +#include "components/prefs/scoped_user_pref_update.h"
  3847. +#include "components/pref_registry/pref_registry_syncable.h"
  3848. +#include "user_script_prefs.h"
  3849. +#include "user_script_pref_info.h"
  3850. +#include "../common/user_script.h"
  3851. +#include "../common/user_scripts_features.h"
  3852. +
  3853. +namespace user_scripts {
  3854. +
  3855. +namespace prefs {
  3856. + const char kUserScriptsEnabled[] = "userscripts.enabled";
  3857. +}
  3858. +
  3859. +namespace {
  3860. +
  3861. +const char kUserScriptsStartup[] = "userscripts.startup";
  3862. +
  3863. +const char kUserScriptsList[] = "userscripts.scripts";
  3864. +const char kScriptIsEnabled[] = "enabled";
  3865. +const char kScriptName[] = "name";
  3866. +const char kScriptDescription[] = "description";
  3867. +const char kScriptVersion[] = "version";
  3868. +const char kScriptInstallTime[] = "install_time";
  3869. +const char kScriptFilePath[] = "file_path";
  3870. +const char kScriptUrlSource[] = "url_source";
  3871. +const char kScriptParserError[] = "parser_error";
  3872. +const char kScriptForceDisabled[] = "force_disabled";
  3873. +
  3874. +class PrefUpdate : public DictionaryPrefUpdate {
  3875. + public:
  3876. + PrefUpdate(PrefService* service,
  3877. + const std::string& id,
  3878. + const std::string& path)
  3879. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3880. +
  3881. + PrefUpdate(const PrefUpdate&) = delete;
  3882. + PrefUpdate& operator=(const PrefUpdate&) = delete;
  3883. + ~PrefUpdate() override = default;
  3884. +
  3885. + base::Value* Get() override {
  3886. + base::Value* dict = DictionaryPrefUpdate::Get();
  3887. + base::Value* dict_item =
  3888. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3889. + if (!dict_item)
  3890. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3891. + return dict_item;
  3892. + }
  3893. +
  3894. + private:
  3895. + const std::string id_;
  3896. +};
  3897. +
  3898. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3899. + const std::string& key,
  3900. + int64_t* value) {
  3901. + DCHECK(dict);
  3902. + const std::string* value_str = dict->FindStringKey(key);
  3903. + if (!value_str) {
  3904. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3905. + << ".";
  3906. + return false;
  3907. + }
  3908. +
  3909. + if (!base::StringToInt64(*value_str, value)) {
  3910. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3911. + << *value_str << ".";
  3912. + return false;
  3913. + }
  3914. +
  3915. + return true;
  3916. +}
  3917. +
  3918. +}
  3919. +
  3920. +UserScriptsPrefs::UserScriptsPrefs(
  3921. + PrefService* prefs)
  3922. + : prefs_(prefs) {
  3923. +}
  3924. +
  3925. +// static
  3926. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3927. + registry->RegisterBooleanPref(prefs::kUserScriptsEnabled, false);
  3928. + registry->RegisterIntegerPref(kUserScriptsStartup, 0);
  3929. + registry->RegisterDictionaryPref(kUserScriptsList);
  3930. +}
  3931. +
  3932. +bool UserScriptsPrefs::IsEnabled() {
  3933. + return prefs_->GetBoolean(prefs::kUserScriptsEnabled);
  3934. +}
  3935. +
  3936. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3937. + prefs_->SetBoolean(prefs::kUserScriptsEnabled, enabled);
  3938. + prefs_->CommitPendingWrite();
  3939. +}
  3940. +
  3941. +void UserScriptsPrefs::StartupTryout(int number) {
  3942. + prefs_->SetInteger(kUserScriptsStartup, number);
  3943. + prefs_->CommitPendingWrite();
  3944. +}
  3945. +
  3946. +int UserScriptsPrefs::GetCurrentStartupTryout() {
  3947. + return prefs_->GetInteger(kUserScriptsStartup);
  3948. +}
  3949. +
  3950. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3951. + if (IsEnabled() == false) {
  3952. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3953. + LOG(INFO) << "UserScriptsPrefs: disabled by user";
  3954. +
  3955. + user_scripts.clear();
  3956. + return;
  3957. + }
  3958. +
  3959. + std::vector<std::string> all_scripts;
  3960. +
  3961. + auto it = user_scripts.begin();
  3962. + while (it != user_scripts.end())
  3963. + {
  3964. + std::string key = it->get()->key();
  3965. + all_scripts.push_back(key);
  3966. +
  3967. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  3968. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  3969. +
  3970. + // add or update prefs
  3971. + scriptInfo->set_name(it->get()->name());
  3972. + scriptInfo->set_description(it->get()->description());
  3973. + scriptInfo->set_version(it->get()->version());
  3974. + scriptInfo->set_file_path(it->get()->file_path());
  3975. + scriptInfo->set_url_source(it->get()->url_source());
  3976. + scriptInfo->set_parser_error(it->get()->parser_error());
  3977. + scriptInfo->force_disabled = (it->get()->force_disabled());
  3978. +
  3979. + PrefUpdate update(prefs_, key, kUserScriptsList);
  3980. + base::Value* script_dict = update.Get();
  3981. +
  3982. + script_dict->SetStringKey(kScriptName, scriptInfo->name());
  3983. + script_dict->SetStringKey(kScriptDescription, scriptInfo->description());
  3984. + script_dict->SetBoolKey(kScriptIsEnabled, scriptInfo->enabled);
  3985. + script_dict->SetStringKey(kScriptVersion, scriptInfo->version());
  3986. + script_dict->SetStringKey(kScriptFilePath, scriptInfo->file_path());
  3987. + script_dict->SetStringKey(kScriptUrlSource, scriptInfo->url_source());
  3988. + script_dict->SetStringKey(kScriptParserError, scriptInfo->parser_error());
  3989. + script_dict->SetBoolKey(kScriptForceDisabled, scriptInfo->force_disabled);
  3990. +
  3991. + std::string install_time_str =
  3992. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  3993. + script_dict->SetStringKey(kScriptInstallTime, install_time_str);
  3994. +
  3995. + if (!scriptInfo->enabled) {
  3996. + it = user_scripts.erase(it);
  3997. + } else {
  3998. + ++it;
  3999. + }
  4000. + }
  4001. +
  4002. + // remove script from prefs if no more present
  4003. + std::vector<std::string> all_scripts_to_remove;
  4004. + const base::DictionaryValue* dict =
  4005. + &base::Value::AsDictionaryValue(*prefs_->GetDictionary(
  4006. + kUserScriptsList));
  4007. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  4008. + script_it.Advance()) {
  4009. + const std::string& key = script_it.key();
  4010. +
  4011. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  4012. + all_scripts_to_remove.push_back(key);
  4013. + }
  4014. + }
  4015. +
  4016. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4017. + base::Value* const update_dict = update.Get();
  4018. + for (auto key : all_scripts_to_remove) {
  4019. + update_dict->RemoveKey(key);
  4020. + }
  4021. +
  4022. + return;
  4023. +}
  4024. +
  4025. +std::string UserScriptsPrefs::GetScriptsInfo() {
  4026. + std::string json_string;
  4027. +
  4028. + const base::Value* dict =
  4029. + prefs_->GetDictionary(kUserScriptsList);
  4030. +
  4031. + if (dict) {
  4032. + base::JSONWriter::WriteWithOptions(
  4033. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  4034. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  4035. + }
  4036. +
  4037. + return json_string;
  4038. +}
  4039. +
  4040. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  4041. + const std::string& script_id) const {
  4042. +
  4043. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  4044. + script_id, "", base::Time::Now(), false);
  4045. +
  4046. + const base::Value* scripts =
  4047. + prefs_->GetDictionary(kUserScriptsList);
  4048. + if (!scripts)
  4049. + return scriptInfo;
  4050. +
  4051. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  4052. + scripts->FindDictKey(script_id));
  4053. + if (!script)
  4054. + return scriptInfo;
  4055. +
  4056. + const std::string* name = script->FindStringKey(kScriptName);
  4057. + const std::string* description = script->FindStringKey(kScriptDescription);
  4058. + const std::string* version = script->FindStringKey(kScriptVersion);
  4059. + const std::string* file_path = script->FindStringKey(kScriptFilePath);
  4060. + const std::string* url_source = script->FindStringKey(kScriptUrlSource);
  4061. + const std::string* parser_error = script->FindStringKey(kScriptParserError);
  4062. +
  4063. + scriptInfo->set_name( name ? *name : "no name" );
  4064. + scriptInfo->set_description( description ? *description : "no description" );
  4065. + scriptInfo->set_version( version ? *version : "no version" );
  4066. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  4067. + scriptInfo->set_file_path( file_path ? *file_path : "no file path" );
  4068. + scriptInfo->set_url_source( url_source ? *url_source : "" );
  4069. + scriptInfo->set_parser_error( parser_error ? *parser_error : "" );
  4070. + scriptInfo->force_disabled = script->FindBoolKey(kScriptForceDisabled).value_or(false);
  4071. +
  4072. + int64_t time_interval = 0;
  4073. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  4074. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  4075. + }
  4076. +
  4077. + return scriptInfo;
  4078. +}
  4079. +
  4080. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  4081. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  4082. + base::Value* const update_dict = update.Get();
  4083. + update_dict->RemoveKey(script_id);
  4084. +}
  4085. +
  4086. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  4087. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  4088. + base::Value* script_dict = update.Get();
  4089. + if (script_dict->FindBoolKey(kScriptForceDisabled).value_or(false))
  4090. + is_enabled = true;
  4091. + script_dict->SetBoolKey(kScriptIsEnabled, is_enabled);
  4092. +}
  4093. +
  4094. +}
  4095. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  4096. new file mode 100644
  4097. --- /dev/null
  4098. +++ b/components/user_scripts/browser/user_script_prefs.h
  4099. @@ -0,0 +1,62 @@
  4100. +/*
  4101. + This file is part of Bromite.
  4102. +
  4103. + Bromite is free software: you can redistribute it and/or modify
  4104. + it under the terms of the GNU General Public License as published by
  4105. + the Free Software Foundation, either version 3 of the License, or
  4106. + (at your option) any later version.
  4107. +
  4108. + Bromite is distributed in the hope that it will be useful,
  4109. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4110. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4111. + GNU General Public License for more details.
  4112. +
  4113. + You should have received a copy of the GNU General Public License
  4114. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4115. +*/
  4116. +
  4117. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4118. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4119. +
  4120. +#include "content/public/browser/browser_context.h"
  4121. +#include "components/prefs/pref_service.h"
  4122. +#include "components/pref_registry/pref_registry_syncable.h"
  4123. +
  4124. +#include "user_script_pref_info.h"
  4125. +#include "../common/user_script.h"
  4126. +
  4127. +namespace user_scripts {
  4128. +
  4129. +namespace prefs {
  4130. + extern const char kUserScriptsEnabled[];
  4131. +}
  4132. +
  4133. +class UserScriptsPrefs {
  4134. + public:
  4135. + UserScriptsPrefs(
  4136. + PrefService* prefs);
  4137. +
  4138. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  4139. +
  4140. + bool IsEnabled();
  4141. + void SetEnabled(bool enabled);
  4142. +
  4143. + void StartupTryout(int number);
  4144. + int GetCurrentStartupTryout();
  4145. +
  4146. + void CompareWithPrefs(UserScriptList& user_scripts);
  4147. +
  4148. + std::string GetScriptsInfo();
  4149. + void RemoveScriptFromPrefs(const std::string& script_id);
  4150. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  4151. +
  4152. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  4153. + const std::string& script_id) const;
  4154. +
  4155. + private:
  4156. + PrefService* prefs_;
  4157. +};
  4158. +
  4159. +}
  4160. +
  4161. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4162. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  4163. new file mode 100755
  4164. --- /dev/null
  4165. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  4166. @@ -0,0 +1,78 @@
  4167. +/*
  4168. + This file is part of Bromite.
  4169. +
  4170. + Bromite is free software: you can redistribute it and/or modify
  4171. + it under the terms of the GNU General Public License as published by
  4172. + the Free Software Foundation, either version 3 of the License, or
  4173. + (at your option) any later version.
  4174. +
  4175. + Bromite is distributed in the hope that it will be useful,
  4176. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4177. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4178. + GNU General Public License for more details.
  4179. +
  4180. + You should have received a copy of the GNU General Public License
  4181. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4182. +*/
  4183. +
  4184. +#include "userscripts_browser_client.h"
  4185. +
  4186. +#include "base/logging.h"
  4187. +
  4188. +#include "chrome/browser/browser_process.h"
  4189. +
  4190. +#include "chrome/browser/profiles/profile.h"
  4191. +#include "chrome/browser/profiles/profile_manager.h"
  4192. +
  4193. +#include "../common/user_scripts_features.h"
  4194. +#include "user_script_loader.h"
  4195. +#include "file_task_runner.h"
  4196. +#include "user_script_prefs.h"
  4197. +
  4198. +namespace user_scripts {
  4199. +
  4200. +namespace {
  4201. +
  4202. +// remember: was ExtensionsBrowserClient
  4203. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  4204. +
  4205. +} // namespace
  4206. +
  4207. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  4208. +
  4209. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  4210. +
  4211. +// static
  4212. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  4213. + // only for browser process
  4214. + if (!g_browser_process)
  4215. + return NULL;
  4216. +
  4217. + // singleton
  4218. + if (g_userscripts_browser_client)
  4219. + return g_userscripts_browser_client;
  4220. +
  4221. + // make file task runner
  4222. + GetUserScriptsFileTaskRunner().get();
  4223. +
  4224. + // new instance singleton
  4225. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  4226. +
  4227. + return g_userscripts_browser_client;
  4228. +}
  4229. +
  4230. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  4231. + browser_context_ = context;
  4232. +
  4233. + prefs_ =
  4234. + std::make_unique<user_scripts::UserScriptsPrefs>(
  4235. + static_cast<Profile*>(context)->GetPrefs());
  4236. +
  4237. + userscript_loader_ =
  4238. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  4239. + if (prefs_->IsEnabled()) {
  4240. + userscript_loader_->SetReady(true);
  4241. + }
  4242. +}
  4243. +
  4244. +} // namespace user_scripts
  4245. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  4246. new file mode 100755
  4247. --- /dev/null
  4248. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  4249. @@ -0,0 +1,62 @@
  4250. +/*
  4251. + This file is part of Bromite.
  4252. +
  4253. + Bromite is free software: you can redistribute it and/or modify
  4254. + it under the terms of the GNU General Public License as published by
  4255. + the Free Software Foundation, either version 3 of the License, or
  4256. + (at your option) any later version.
  4257. +
  4258. + Bromite is distributed in the hope that it will be useful,
  4259. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4260. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4261. + GNU General Public License for more details.
  4262. +
  4263. + You should have received a copy of the GNU General Public License
  4264. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4265. +*/
  4266. +
  4267. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4268. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4269. +
  4270. +#include <memory>
  4271. +#include <string>
  4272. +#include <vector>
  4273. +
  4274. +#include "content/public/browser/browser_context.h"
  4275. +
  4276. +#include "../common/user_script.h"
  4277. +#include "user_script_loader.h"
  4278. +#include "user_script_prefs.h"
  4279. +
  4280. +namespace user_scripts {
  4281. +
  4282. +class UserScriptsBrowserClient {
  4283. + public:
  4284. + UserScriptsBrowserClient();
  4285. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  4286. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  4287. + virtual ~UserScriptsBrowserClient();
  4288. +
  4289. + // Returns the single instance of |this|.
  4290. + static UserScriptsBrowserClient* GetInstance();
  4291. +
  4292. + void SetProfile(content::BrowserContext* context);
  4293. +
  4294. + user_scripts::UserScriptsPrefs* GetPrefs() {
  4295. + return prefs_.get();
  4296. + }
  4297. +
  4298. + user_scripts::UserScriptLoader* GetLoader() {
  4299. + return userscript_loader_.get();
  4300. + }
  4301. +
  4302. + private:
  4303. + std::unique_ptr<UserScriptList> scripts_;
  4304. + content::BrowserContext* browser_context_;
  4305. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  4306. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  4307. +};
  4308. +
  4309. +} // namespace extensions
  4310. +
  4311. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4312. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  4313. new file mode 100755
  4314. --- /dev/null
  4315. +++ b/components/user_scripts/common/BUILD.gn
  4316. @@ -0,0 +1,49 @@
  4317. +# Copyright 2014 The Chromium Authors. All rights reserved.
  4318. +# Use of this source code is governed by a BSD-style license that can be
  4319. +# found in the LICENSE file.
  4320. +
  4321. +import("//build/config/features.gni")
  4322. +import("//mojo/public/tools/bindings/mojom.gni")
  4323. +
  4324. +static_library("common") {
  4325. + sources = [
  4326. + "user_scripts_features.cc",
  4327. + "user_scripts_features.h",
  4328. + "constants.h",
  4329. + "host_id.cc",
  4330. + "host_id.h",
  4331. + "script_constants.h",
  4332. + "url_pattern_set.cc",
  4333. + "url_pattern_set.h",
  4334. + "url_pattern.cc",
  4335. + "url_pattern.h",
  4336. + "user_script.cc",
  4337. + "user_script.h",
  4338. + "view_type.cc",
  4339. + "view_type.h",
  4340. + "extension_messages.cc",
  4341. + "extension_messages.h",
  4342. + "extension_message_generator.cc",
  4343. + "extension_message_generator.h",
  4344. + ]
  4345. +
  4346. + configs += [
  4347. + "//build/config:precompiled_headers",
  4348. + "//build/config/compiler:wexit_time_destructors",
  4349. + ]
  4350. +
  4351. + public_deps = [
  4352. + "//components/services/app_service/public/cpp:app_file_handling",
  4353. + "//content/public/common",
  4354. + "//ipc",
  4355. + "//skia",
  4356. + ]
  4357. +
  4358. + deps = [
  4359. + "//base",
  4360. + "//components/url_formatter",
  4361. + "//components/url_matcher",
  4362. + "//components/version_info",
  4363. + "//crypto",
  4364. + ]
  4365. +}
  4366. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  4367. new file mode 100755
  4368. --- /dev/null
  4369. +++ b/components/user_scripts/common/constants.h
  4370. @@ -0,0 +1,21 @@
  4371. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4372. +// Use of this source code is governed by a BSD-style license that can be
  4373. +// found in the LICENSE file.
  4374. +
  4375. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  4376. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  4377. +
  4378. +#include "base/files/file_path.h"
  4379. +#include "base/strings/string_piece_forward.h"
  4380. +#include "components/services/app_service/public/mojom/types.mojom.h"
  4381. +#include "components/version_info/channel.h"
  4382. +#include "ui/base/layout.h"
  4383. +
  4384. +namespace user_scripts {
  4385. +
  4386. +// The origin of injected CSS.
  4387. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  4388. +
  4389. +} // namespace user_scripts
  4390. +
  4391. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  4392. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  4393. new file mode 100755
  4394. --- /dev/null
  4395. +++ b/components/user_scripts/common/error_utils.cc
  4396. @@ -0,0 +1,54 @@
  4397. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4398. +// Use of this source code is governed by a BSD-style license that can be
  4399. +// found in the LICENSE file.
  4400. +
  4401. +#include "error_utils.h"
  4402. +
  4403. +#include <initializer_list>
  4404. +
  4405. +#include "base/check_op.h"
  4406. +#include "base/strings/string_tokenizer.h"
  4407. +#include "base/strings/string_util.h"
  4408. +#include "base/strings/utf_string_conversions.h"
  4409. +
  4410. +namespace user_scripts {
  4411. +
  4412. +namespace {
  4413. +
  4414. +std::string FormatErrorMessageInternal(
  4415. + base::StringPiece format,
  4416. + std::initializer_list<base::StringPiece> args) {
  4417. + std::string format_str = format.as_string();
  4418. + base::StringTokenizer tokenizer(format_str, "*");
  4419. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  4420. +
  4421. + std::vector<base::StringPiece> result_pieces;
  4422. + auto* args_it = args.begin();
  4423. + while (tokenizer.GetNext()) {
  4424. + if (!tokenizer.token_is_delim()) {
  4425. + result_pieces.push_back(tokenizer.token_piece());
  4426. + continue;
  4427. + }
  4428. +
  4429. + CHECK_NE(args_it, args.end())
  4430. + << "More placeholders (*) than substitutions.";
  4431. +
  4432. + // Substitute the argument.
  4433. + result_pieces.push_back(*args_it);
  4434. + args_it++;
  4435. + }
  4436. +
  4437. + // Not all substitutions were consumed.
  4438. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  4439. +
  4440. + return base::JoinString(result_pieces, "" /* separator */);
  4441. +}
  4442. +
  4443. +} // namespace
  4444. +
  4445. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  4446. + base::StringPiece s1) {
  4447. + return FormatErrorMessageInternal(format, {s1});
  4448. +}
  4449. +
  4450. +} // namespace user_scripts
  4451. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  4452. new file mode 100755
  4453. --- /dev/null
  4454. +++ b/components/user_scripts/common/error_utils.h
  4455. @@ -0,0 +1,24 @@
  4456. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4457. +// Use of this source code is governed by a BSD-style license that can be
  4458. +// found in the LICENSE file.
  4459. +
  4460. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4461. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4462. +
  4463. +#include <string>
  4464. +
  4465. +#include "base/strings/string_piece.h"
  4466. +
  4467. +namespace user_scripts {
  4468. +
  4469. +class ErrorUtils {
  4470. + public:
  4471. + // Creates an error messages from a pattern.
  4472. + static std::string FormatErrorMessage(base::StringPiece format,
  4473. + base::StringPiece s1);
  4474. +
  4475. +};
  4476. +
  4477. +} // namespace extensions
  4478. +
  4479. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4480. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  4481. new file mode 100755
  4482. --- /dev/null
  4483. +++ b/components/user_scripts/common/extension_message_generator.cc
  4484. @@ -0,0 +1,29 @@
  4485. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4486. +// Use of this source code is governed by a BSD-style license that can be
  4487. +// found in the LICENSE file.
  4488. +
  4489. +// Get basic type definitions.
  4490. +#define IPC_MESSAGE_IMPL
  4491. +#include "components/user_scripts/common/extension_message_generator.h"
  4492. +
  4493. +// Generate constructors.
  4494. +#include "ipc/struct_constructor_macros.h"
  4495. +#include "components/user_scripts/common/extension_message_generator.h"
  4496. +
  4497. +// Generate param traits write methods.
  4498. +#include "ipc/param_traits_write_macros.h"
  4499. +namespace IPC {
  4500. +#include "components/user_scripts/common/extension_message_generator.h"
  4501. +} // namespace IPC
  4502. +
  4503. +// Generate param traits read methods.
  4504. +#include "ipc/param_traits_read_macros.h"
  4505. +namespace IPC {
  4506. +#include "components/user_scripts/common/extension_message_generator.h"
  4507. +} // namespace IPC
  4508. +
  4509. +// Generate param traits log methods.
  4510. +#include "ipc/param_traits_log_macros.h"
  4511. +namespace IPC {
  4512. +#include "components/user_scripts/common/extension_message_generator.h"
  4513. +} // namespace IPC
  4514. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  4515. new file mode 100755
  4516. --- /dev/null
  4517. +++ b/components/user_scripts/common/extension_message_generator.h
  4518. @@ -0,0 +1,11 @@
  4519. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4520. +// Use of this source code is governed by a BSD-style license that can be
  4521. +// found in the LICENSE file.
  4522. +
  4523. +// Multiply-included file, hence no include guard.
  4524. +
  4525. +#undef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4526. +#include "extension_messages.h"
  4527. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4528. +#error "Failed to include header extension_messages.h"
  4529. +#endif
  4530. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  4531. new file mode 100755
  4532. --- /dev/null
  4533. +++ b/components/user_scripts/common/extension_messages.cc
  4534. @@ -0,0 +1,40 @@
  4535. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4536. +// Use of this source code is governed by a BSD-style license that can be
  4537. +// found in the LICENSE file.
  4538. +
  4539. +#include "extension_messages.h"
  4540. +
  4541. +#include <stddef.h>
  4542. +
  4543. +#include <memory>
  4544. +#include <utility>
  4545. +
  4546. +#include "content/public/common/common_param_traits.h"
  4547. +
  4548. +namespace IPC {
  4549. +
  4550. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  4551. + WriteParam(m, p.type());
  4552. + WriteParam(m, p.id());
  4553. +}
  4554. +
  4555. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  4556. + base::PickleIterator* iter,
  4557. + param_type* r) {
  4558. + HostID::HostType type;
  4559. + std::string id;
  4560. + if (!ReadParam(m, iter, &type))
  4561. + return false;
  4562. + if (!ReadParam(m, iter, &id))
  4563. + return false;
  4564. + *r = HostID(type, id);
  4565. + return true;
  4566. +}
  4567. +
  4568. +void ParamTraits<HostID>::Log(
  4569. + const param_type& p, std::string* l) {
  4570. + LogParam(p.type(), l);
  4571. + LogParam(p.id(), l);
  4572. +}
  4573. +
  4574. +} // namespace IPC
  4575. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  4576. new file mode 100755
  4577. --- /dev/null
  4578. +++ b/components/user_scripts/common/extension_messages.h
  4579. @@ -0,0 +1,70 @@
  4580. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4581. +// Use of this source code is governed by a BSD-style license that can be
  4582. +// found in the LICENSE file.
  4583. +
  4584. +// IPC messages for extensions.
  4585. +
  4586. +#ifndef USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4587. +#define USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4588. +
  4589. +#include <stdint.h>
  4590. +
  4591. +#include <map>
  4592. +#include <memory>
  4593. +#include <set>
  4594. +#include <string>
  4595. +#include <vector>
  4596. +
  4597. +#include "base/memory/read_only_shared_memory_region.h"
  4598. +#include "base/values.h"
  4599. +#include "content/public/common/common_param_traits.h"
  4600. +#include "constants.h"
  4601. +#include "host_id.h"
  4602. +#include "ipc/ipc_message_start.h"
  4603. +#include "ipc/ipc_message_macros.h"
  4604. +#include "url/gurl.h"
  4605. +#include "url/origin.h"
  4606. +
  4607. +#define IPC_MESSAGE_START ExtensionMsgStart
  4608. +
  4609. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  4610. +
  4611. +// Singly-included section for custom IPC traits.
  4612. +#ifndef INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4613. +#define INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4614. +
  4615. +namespace IPC {
  4616. +
  4617. +template <>
  4618. +struct ParamTraits<HostID> {
  4619. + typedef HostID param_type;
  4620. + static void Write(base::Pickle* m, const param_type& p);
  4621. + static bool Read(const base::Pickle* m,
  4622. + base::PickleIterator* iter,
  4623. + param_type* r);
  4624. + static void Log(const param_type& p, std::string* l);
  4625. +};
  4626. +
  4627. +
  4628. +} // namespace IPC
  4629. +
  4630. +#endif // INTERNAL_USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4631. +
  4632. +// Notification that the user scripts have been updated. It has one
  4633. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  4634. +// This memory region is valid in the context of the renderer.
  4635. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  4636. +// programmatically-defined scripts. Otherwise, the handle refers to all
  4637. +// hosts' statically defined scripts. So far, only extension-hosts support
  4638. +// statically defined scripts; WebUI-hosts don't.
  4639. +// If |changed_hosts| is not empty, only the host in that set will
  4640. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  4641. +// region will be updated. Note that the empty set => all hosts case is not
  4642. +// supported for per-extension programmatically-defined script regions; in such
  4643. +// regions, the owner is expected to list itself as the only changed host.
  4644. +// If |whitelisted_only| is true, this process should only run whitelisted
  4645. +// scripts and not all user scripts.
  4646. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  4647. + base::ReadOnlySharedMemoryRegion)
  4648. +
  4649. +#endif // USERSCRIPTS_COMMON_EXTENSION_MESSAGES_H_
  4650. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  4651. new file mode 100755
  4652. --- /dev/null
  4653. +++ b/components/user_scripts/common/host_id.cc
  4654. @@ -0,0 +1,31 @@
  4655. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4656. +// Use of this source code is governed by a BSD-style license that can be
  4657. +// found in the LICENSE file.
  4658. +
  4659. +#include "host_id.h"
  4660. +
  4661. +#include <tuple>
  4662. +
  4663. +HostID::HostID()
  4664. + : type_(HostType::EXTENSIONS) {
  4665. +}
  4666. +
  4667. +HostID::HostID(HostType type, const std::string& id)
  4668. + : type_(type), id_(id) {
  4669. +}
  4670. +
  4671. +HostID::HostID(const HostID& host_id)
  4672. + : type_(host_id.type()),
  4673. + id_(host_id.id()) {
  4674. +}
  4675. +
  4676. +HostID::~HostID() {
  4677. +}
  4678. +
  4679. +bool HostID::operator<(const HostID& host_id) const {
  4680. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  4681. +}
  4682. +
  4683. +bool HostID::operator==(const HostID& host_id) const {
  4684. + return type_ == host_id.type_ && id_ == host_id.id_;
  4685. +}
  4686. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  4687. new file mode 100755
  4688. --- /dev/null
  4689. +++ b/components/user_scripts/common/host_id.h
  4690. @@ -0,0 +1,35 @@
  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. +#ifndef USERSCRIPTS_COMMON_HOST_ID_H_
  4696. +#define USERSCRIPTS_COMMON_HOST_ID_H_
  4697. +
  4698. +#include <string>
  4699. +
  4700. +// IDs of hosts who own user scripts.
  4701. +// A HostID is immutable after creation.
  4702. +struct HostID {
  4703. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  4704. +
  4705. + HostID();
  4706. + HostID(HostType type, const std::string& id);
  4707. + HostID(const HostID& host_id);
  4708. + ~HostID();
  4709. +
  4710. + bool operator<(const HostID& host_id) const;
  4711. + bool operator==(const HostID& host_id) const;
  4712. +
  4713. + HostType type() const { return type_; }
  4714. + const std::string& id() const { return id_; }
  4715. +
  4716. + private:
  4717. + // The type of the host.
  4718. + HostType type_;
  4719. +
  4720. + // Similar to extension_id, host_id is a unique indentifier for a host,
  4721. + // e.g., an Extension or WebUI.
  4722. + std::string id_;
  4723. +};
  4724. +
  4725. +#endif // USERSCRIPTS_COMMON_HOST_ID_H_
  4726. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  4727. new file mode 100755
  4728. --- /dev/null
  4729. +++ b/components/user_scripts/common/script_constants.h
  4730. @@ -0,0 +1,33 @@
  4731. +// Copyright 2020 The Chromium Authors. All rights reserved.
  4732. +// Use of this source code is governed by a BSD-style license that can be
  4733. +// found in the LICENSE file.
  4734. +
  4735. +#ifndef USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4736. +#define USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4737. +
  4738. +namespace user_scripts {
  4739. +
  4740. +// Whether to fall back to matching the origin for frames where the URL
  4741. +// cannot be matched directly, such as those with about: or data: schemes.
  4742. +enum class MatchOriginAsFallbackBehavior {
  4743. + // Never fall back on the origin; this means scripts will never match on
  4744. + // these frames.
  4745. + kNever,
  4746. + // Match the origin only for about:-scheme frames, and then climb the frame
  4747. + // tree to find an appropriate ancestor to get a full URL (including path).
  4748. + // This is for supporting the "match_about_blank" key.
  4749. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  4750. + // and not worry about climbing the frame tree. It would be a behavior
  4751. + // change, but I wonder how many extensions it would impact in practice.
  4752. + kMatchForAboutSchemeAndClimbTree,
  4753. + // Match the origin as a fallback whenever applicable. This won't have a
  4754. + // corresponding path.
  4755. + kAlways,
  4756. +};
  4757. +
  4758. +// TODO(devlin): Move the other non-UserScript-specific constants like
  4759. +// RunLocation and InjectionType from UserScript into here.
  4760. +
  4761. +}
  4762. +
  4763. +#endif // USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4764. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  4765. new file mode 100755
  4766. --- /dev/null
  4767. +++ b/components/user_scripts/common/url_pattern.cc
  4768. @@ -0,0 +1,803 @@
  4769. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4770. +// Use of this source code is governed by a BSD-style license that can be
  4771. +// found in the LICENSE file.
  4772. +
  4773. +#include "url_pattern.h"
  4774. +
  4775. +#include <stddef.h>
  4776. +
  4777. +#include <ostream>
  4778. +
  4779. +#include "base/logging.h"
  4780. +#include "base/strings/pattern.h"
  4781. +#include "base/strings/strcat.h"
  4782. +#include "base/strings/string_number_conversions.h"
  4783. +#include "base/strings/string_piece.h"
  4784. +#include "base/strings/string_split.h"
  4785. +#include "base/strings/string_util.h"
  4786. +#include "base/strings/stringprintf.h"
  4787. +#include "content/public/common/url_constants.h"
  4788. +#include "constants.h"
  4789. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4790. +#include "net/base/url_util.h"
  4791. +#include "url/gurl.h"
  4792. +#include "url/url_util.h"
  4793. +
  4794. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4795. +
  4796. +namespace {
  4797. +
  4798. +// TODO(aa): What about more obscure schemes like javascript: ?
  4799. +// Note: keep this array in sync with kValidSchemeMasks.
  4800. +const char* const kValidSchemes[] = {
  4801. + url::kHttpScheme, url::kHttpsScheme,
  4802. + url::kFileScheme, url::kFtpScheme,
  4803. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4804. + url::kFileSystemScheme, url::kWsScheme,
  4805. + url::kWssScheme, url::kDataScheme,
  4806. + url::kUrnScheme,
  4807. +};
  4808. +
  4809. +const int kValidSchemeMasks[] = {
  4810. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4811. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4812. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4813. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4814. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4815. + URLPattern::SCHEME_URN,
  4816. +};
  4817. +
  4818. +static_assert(std::size(kValidSchemes) == std::size(kValidSchemeMasks),
  4819. + "must keep these arrays in sync");
  4820. +
  4821. +const char kParseSuccess[] = "Success.";
  4822. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4823. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4824. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4825. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4826. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4827. +const char kParseErrorEmptyPath[] = "Empty path.";
  4828. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4829. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4830. +
  4831. +// Message explaining each URLPattern::ParseResult.
  4832. +const char* const kParseResultMessages[] = {
  4833. + kParseSuccess,
  4834. + kParseErrorMissingSchemeSeparator,
  4835. + kParseErrorInvalidScheme,
  4836. + kParseErrorWrongSchemeType,
  4837. + kParseErrorEmptyHost,
  4838. + kParseErrorInvalidHostWildcard,
  4839. + kParseErrorEmptyPath,
  4840. + kParseErrorInvalidPort,
  4841. + kParseErrorInvalidHost,
  4842. +};
  4843. +
  4844. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4845. + std::size(kParseResultMessages),
  4846. + "must add message for each parse result");
  4847. +
  4848. +const char kPathSeparator[] = "/";
  4849. +
  4850. +bool IsStandardScheme(base::StringPiece scheme) {
  4851. + // "*" gets the same treatment as a standard scheme.
  4852. + if (scheme == "*")
  4853. + return true;
  4854. +
  4855. + return url::IsStandard(scheme.data(),
  4856. + url::Component(0, static_cast<int>(scheme.length())));
  4857. +}
  4858. +
  4859. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4860. + if (port == "*")
  4861. + return true;
  4862. +
  4863. + // Only accept non-wildcard ports if the scheme uses ports.
  4864. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4865. + url::PORT_UNSPECIFIED) {
  4866. + return false;
  4867. + }
  4868. +
  4869. + int parsed_port = url::PORT_UNSPECIFIED;
  4870. + if (!base::StringToInt(port, &parsed_port))
  4871. + return false;
  4872. + return (parsed_port >= 0) && (parsed_port < 65536);
  4873. +}
  4874. +
  4875. +// Returns |path| with the trailing wildcard stripped if one existed.
  4876. +//
  4877. +// The functions that rely on this (OverlapsWith and Contains) are only
  4878. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4879. +// the path will have only a single wildcard at the end. This makes figuring
  4880. +// out overlap much easier. It seems like there is probably a computer-sciency
  4881. +// way to solve the general case, but we don't need that yet.
  4882. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4883. + if (base::EndsWith(path, "*"))
  4884. + path.remove_suffix(1);
  4885. + return path;
  4886. +}
  4887. +
  4888. +// Removes trailing dot from |host_piece| if any.
  4889. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4890. + if (base::EndsWith(host_piece, "."))
  4891. + host_piece.remove_suffix(1);
  4892. + return host_piece;
  4893. +}
  4894. +
  4895. +} // namespace
  4896. +
  4897. +// static
  4898. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4899. + for (size_t i = 0; i < std::size(kValidSchemes); ++i) {
  4900. + if (scheme == kValidSchemes[i])
  4901. + return true;
  4902. + }
  4903. + return false;
  4904. +}
  4905. +
  4906. +// static
  4907. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4908. + int result = 0;
  4909. + for (size_t i = 0; i < std::size(kValidSchemeMasks); ++i)
  4910. + result |= kValidSchemeMasks[i];
  4911. + return result;
  4912. +}
  4913. +
  4914. +URLPattern::URLPattern()
  4915. + : valid_schemes_(SCHEME_NONE),
  4916. + match_all_urls_(false),
  4917. + match_subdomains_(false),
  4918. + port_("*") {}
  4919. +
  4920. +URLPattern::URLPattern(int valid_schemes)
  4921. + : valid_schemes_(valid_schemes),
  4922. + match_all_urls_(false),
  4923. + match_subdomains_(false),
  4924. + port_("*") {}
  4925. +
  4926. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4927. + // Strict error checking is used, because this constructor is only
  4928. + // appropriate when we know |pattern| is valid.
  4929. + : valid_schemes_(valid_schemes),
  4930. + match_all_urls_(false),
  4931. + match_subdomains_(false),
  4932. + port_("*") {
  4933. + ParseResult result = Parse(pattern);
  4934. + DCHECK_EQ(ParseResult::kSuccess, result)
  4935. + << "Parsing unexpectedly failed for pattern: " << pattern << ": "
  4936. + << GetParseResultString(result);
  4937. +}
  4938. +
  4939. +URLPattern::URLPattern(const URLPattern& other) = default;
  4940. +
  4941. +URLPattern::URLPattern(URLPattern&& other) = default;
  4942. +
  4943. +URLPattern::~URLPattern() {
  4944. +}
  4945. +
  4946. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4947. +
  4948. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4949. +
  4950. +bool URLPattern::operator<(const URLPattern& other) const {
  4951. + return GetAsString() < other.GetAsString();
  4952. +}
  4953. +
  4954. +bool URLPattern::operator>(const URLPattern& other) const {
  4955. + return GetAsString() > other.GetAsString();
  4956. +}
  4957. +
  4958. +bool URLPattern::operator==(const URLPattern& other) const {
  4959. + return GetAsString() == other.GetAsString();
  4960. +}
  4961. +
  4962. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4963. + return out << '"' << url_pattern.GetAsString() << '"';
  4964. +}
  4965. +
  4966. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  4967. + spec_.clear();
  4968. + SetMatchAllURLs(false);
  4969. + SetMatchSubdomains(false);
  4970. + SetPort("*");
  4971. +
  4972. + // Special case pattern to match every valid URL.
  4973. + if (pattern == kAllUrlsPattern) {
  4974. + SetMatchAllURLs(true);
  4975. + return ParseResult::kSuccess;
  4976. + }
  4977. +
  4978. + // Parse out the scheme.
  4979. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  4980. + bool has_standard_scheme_separator = true;
  4981. +
  4982. + // Some urls also use ':' alone as the scheme separator.
  4983. + if (scheme_end_pos == base::StringPiece::npos) {
  4984. + scheme_end_pos = pattern.find(':');
  4985. + has_standard_scheme_separator = false;
  4986. + }
  4987. +
  4988. + if (scheme_end_pos == base::StringPiece::npos)
  4989. + return ParseResult::kMissingSchemeSeparator;
  4990. +
  4991. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  4992. + return ParseResult::kInvalidScheme;
  4993. +
  4994. + bool standard_scheme = IsStandardScheme(scheme_);
  4995. + if (standard_scheme != has_standard_scheme_separator)
  4996. + return ParseResult::kWrongSchemeSeparator;
  4997. +
  4998. + // Advance past the scheme separator.
  4999. + scheme_end_pos +=
  5000. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  5001. + if (scheme_end_pos >= pattern.size())
  5002. + return ParseResult::kEmptyHost;
  5003. +
  5004. + // Parse out the host and path.
  5005. + size_t host_start_pos = scheme_end_pos;
  5006. + size_t path_start_pos = 0;
  5007. +
  5008. + if (!standard_scheme) {
  5009. + path_start_pos = host_start_pos;
  5010. + } else if (scheme_ == url::kFileScheme) {
  5011. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5012. + if (host_end_pos == base::StringPiece::npos) {
  5013. + // Allow hostname omission.
  5014. + // e.g. file://* is interpreted as file:///*,
  5015. + // file://foo* is interpreted as file:///foo*.
  5016. + path_start_pos = host_start_pos - 1;
  5017. + } else {
  5018. + // Ignore hostname if scheme is file://.
  5019. + // e.g. file://localhost/foo is equal to file:///foo.
  5020. + path_start_pos = host_end_pos;
  5021. + }
  5022. + } else {
  5023. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  5024. +
  5025. + // Host is required.
  5026. + if (host_start_pos == host_end_pos)
  5027. + return ParseResult::kEmptyHost;
  5028. +
  5029. + if (host_end_pos == base::StringPiece::npos)
  5030. + return ParseResult::kEmptyPath;
  5031. +
  5032. + base::StringPiece host_and_port =
  5033. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  5034. +
  5035. + size_t port_separator_pos = base::StringPiece::npos;
  5036. + if (host_and_port[0] != '[') {
  5037. + // Not IPv6 (either IPv4 or just a normal address).
  5038. + port_separator_pos = host_and_port.find(':');
  5039. + } else { // IPv6.
  5040. + size_t host_end_pos = host_and_port.find(']');
  5041. + if (host_end_pos == base::StringPiece::npos)
  5042. + return ParseResult::kInvalidHost;
  5043. + if (host_end_pos == 1)
  5044. + return ParseResult::kEmptyHost;
  5045. +
  5046. + if (host_end_pos < host_and_port.length() - 1) {
  5047. + // The host isn't the only component. Check for a port. This would
  5048. + // require a ':' to follow the closing ']' from the host.
  5049. + if (host_and_port[host_end_pos + 1] != ':')
  5050. + return ParseResult::kInvalidHost;
  5051. +
  5052. + port_separator_pos = host_end_pos + 1;
  5053. + }
  5054. + }
  5055. +
  5056. + if (port_separator_pos != base::StringPiece::npos &&
  5057. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  5058. + return ParseResult::kInvalidPort;
  5059. + }
  5060. +
  5061. + // Note: this substr() will be the entire string if the port position
  5062. + // wasn't found.
  5063. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  5064. +
  5065. + if (host_piece.empty())
  5066. + return ParseResult::kEmptyHost;
  5067. +
  5068. + if (host_piece == "*") {
  5069. + match_subdomains_ = true;
  5070. + host_piece = base::StringPiece();
  5071. + } else if (base::StartsWith(host_piece, "*.")) {
  5072. + if (host_piece.length() == 2) {
  5073. + // We don't allow just '*.' as a host.
  5074. + return ParseResult::kEmptyHost;
  5075. + }
  5076. + match_subdomains_ = true;
  5077. + host_piece = host_piece.substr(2);
  5078. + }
  5079. +
  5080. + host_ = std::string(host_piece);
  5081. +
  5082. + path_start_pos = host_end_pos;
  5083. + }
  5084. +
  5085. + SetPath(pattern.substr(path_start_pos));
  5086. +
  5087. + // No other '*' can occur in the host, though. This isn't necessary, but is
  5088. + // done as a convenience to developers who might otherwise be confused and
  5089. + // think '*' works as a glob in the host.
  5090. + if (host_.find('*') != std::string::npos)
  5091. + return ParseResult::kInvalidHostWildcard;
  5092. +
  5093. + if (!host_.empty()) {
  5094. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  5095. + // it.
  5096. + url::CanonHostInfo host_info;
  5097. + host_ = net::CanonicalizeHost(host_, &host_info);
  5098. + // net::CanonicalizeHost() returns an empty string on failure.
  5099. + if (host_.empty())
  5100. + return ParseResult::kInvalidHost;
  5101. + }
  5102. +
  5103. + // Null characters are not allowed in hosts.
  5104. + if (host_.find('\0') != std::string::npos)
  5105. + return ParseResult::kInvalidHost;
  5106. +
  5107. + return ParseResult::kSuccess;
  5108. +}
  5109. +
  5110. +void URLPattern::SetValidSchemes(int valid_schemes) {
  5111. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  5112. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  5113. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  5114. + // http or https).
  5115. + spec_.clear();
  5116. + valid_schemes_ = valid_schemes;
  5117. +}
  5118. +
  5119. +void URLPattern::SetHost(base::StringPiece host) {
  5120. + spec_.clear();
  5121. + host_.assign(host.data(), host.size());
  5122. +}
  5123. +
  5124. +void URLPattern::SetMatchAllURLs(bool val) {
  5125. + spec_.clear();
  5126. + match_all_urls_ = val;
  5127. +
  5128. + if (val) {
  5129. + match_subdomains_ = true;
  5130. + scheme_ = "*";
  5131. + host_.clear();
  5132. + SetPath("/*");
  5133. + }
  5134. +}
  5135. +
  5136. +void URLPattern::SetMatchSubdomains(bool val) {
  5137. + spec_.clear();
  5138. + match_subdomains_ = val;
  5139. +}
  5140. +
  5141. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  5142. + spec_.clear();
  5143. + scheme_.assign(scheme.data(), scheme.size());
  5144. + if (scheme_ == "*") {
  5145. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  5146. + } else if (!IsValidScheme(scheme_)) {
  5147. + return false;
  5148. + }
  5149. + return true;
  5150. +}
  5151. +
  5152. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  5153. + if (valid_schemes_ == SCHEME_ALL)
  5154. + return true;
  5155. +
  5156. + for (size_t i = 0; i < std::size(kValidSchemes); ++i) {
  5157. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  5158. + return true;
  5159. + }
  5160. +
  5161. + return false;
  5162. +}
  5163. +
  5164. +void URLPattern::SetPath(base::StringPiece path) {
  5165. + spec_.clear();
  5166. + path_.assign(path.data(), path.size());
  5167. + path_escaped_ = path_;
  5168. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  5169. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  5170. +}
  5171. +
  5172. +bool URLPattern::SetPort(base::StringPiece port) {
  5173. + spec_.clear();
  5174. + if (IsValidPortForScheme(scheme_, port)) {
  5175. + port_.assign(port.data(), port.size());
  5176. + return true;
  5177. + }
  5178. + return false;
  5179. +}
  5180. +
  5181. +bool URLPattern::MatchesURL(const GURL& test) const {
  5182. + // Invalid URLs can never match.
  5183. + if (!test.is_valid())
  5184. + return false;
  5185. +
  5186. + const GURL* test_url = &test;
  5187. + bool has_inner_url = test.inner_url() != nullptr;
  5188. +
  5189. + if (has_inner_url) {
  5190. + if (!test.SchemeIsFileSystem())
  5191. + return false; // The only nested URLs we handle are filesystem URLs.
  5192. + test_url = test.inner_url();
  5193. + }
  5194. +
  5195. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  5196. + // the scheme is excluded.
  5197. + if (!MatchesScheme(test_url->scheme_piece()))
  5198. + return false;
  5199. +
  5200. + if (match_all_urls_)
  5201. + return true;
  5202. +
  5203. + // Unless |match_all_urls_| is true, the grammar only permits matching
  5204. + // URLs with nonempty paths.
  5205. + if (!test.has_path())
  5206. + return false;
  5207. +
  5208. + std::string path_for_request = test.PathForRequest();
  5209. + if (has_inner_url) {
  5210. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  5211. + path_for_request.c_str());
  5212. + }
  5213. +
  5214. + return MatchesSecurityOriginHelper(*test_url) &&
  5215. + MatchesPath(path_for_request);
  5216. +}
  5217. +
  5218. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  5219. + const GURL* test_url = &test;
  5220. + bool has_inner_url = test.inner_url() != NULL;
  5221. +
  5222. + if (has_inner_url) {
  5223. + if (!test.SchemeIsFileSystem())
  5224. + return false; // The only nested URLs we handle are filesystem URLs.
  5225. + test_url = test.inner_url();
  5226. + }
  5227. +
  5228. + if (!MatchesScheme(test_url->scheme()))
  5229. + return false;
  5230. +
  5231. + if (match_all_urls_)
  5232. + return true;
  5233. +
  5234. + return MatchesSecurityOriginHelper(*test_url);
  5235. +}
  5236. +
  5237. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  5238. + if (!IsValidScheme(test))
  5239. + return false;
  5240. +
  5241. + return scheme_ == "*" || test == scheme_;
  5242. +}
  5243. +
  5244. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  5245. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  5246. + // important that we do this conversion to a GURL in order to canonicalize the
  5247. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  5248. + // just do string comparison.
  5249. + return MatchesHost(
  5250. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  5251. + url::kStandardSchemeSeparator, host.data())));
  5252. +}
  5253. +
  5254. +bool URLPattern::MatchesHost(const GURL& test) const {
  5255. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  5256. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  5257. +
  5258. + // If the hosts are exactly equal, we have a match.
  5259. + if (test_host == pattern_host)
  5260. + return true;
  5261. +
  5262. + // If we're matching subdomains, and we have no host in the match pattern,
  5263. + // that means that we're matching all hosts, which means we have a match no
  5264. + // matter what the test host is.
  5265. + if (match_subdomains_ && pattern_host.empty())
  5266. + return true;
  5267. +
  5268. + // Otherwise, we can only match if our match pattern matches subdomains.
  5269. + if (!match_subdomains_)
  5270. + return false;
  5271. +
  5272. + // We don't do subdomain matching against IP addresses, so we can give up now
  5273. + // if the test host is an IP address.
  5274. + if (test.HostIsIPAddress())
  5275. + return false;
  5276. +
  5277. + // Check if the test host is a subdomain of our host.
  5278. + if (test_host.length() <= (pattern_host.length() + 1))
  5279. + return false;
  5280. +
  5281. + if (!base::EndsWith(test_host, pattern_host))
  5282. + return false;
  5283. +
  5284. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  5285. +}
  5286. +
  5287. +bool URLPattern::MatchesEffectiveTld(
  5288. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  5289. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  5290. + const {
  5291. + // Check if it matches all urls or is a pattern like http://*/*.
  5292. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  5293. + return true;
  5294. +
  5295. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  5296. + if (!match_subdomains_)
  5297. + return false;
  5298. +
  5299. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  5300. + // doesn't match all hosts in an effective TLD.
  5301. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5302. + host_, unknown_filter, private_filter)) {
  5303. + return false;
  5304. + }
  5305. +
  5306. + // At this point the host could either be just a TLD ("com") or some unknown
  5307. + // TLD-like string ("notatld"). To disambiguate between them construct a
  5308. + // fake URL, and check the registry.
  5309. + //
  5310. + // If we recognized this TLD, then this is a pattern like *.com, and it
  5311. + // matches an effective TLD.
  5312. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5313. + "notatld." + host_, unknown_filter, private_filter);
  5314. +}
  5315. +
  5316. +bool URLPattern::MatchesSingleOrigin() const {
  5317. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  5318. + // defaults to *. It's not very interesting anyway, so leave it out.
  5319. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  5320. +}
  5321. +
  5322. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  5323. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  5324. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  5325. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  5326. + if (path_escaped_.length() == test.length() + 2 &&
  5327. + base::StartsWith(path_escaped_.c_str(), test) &&
  5328. + base::EndsWith(path_escaped_, "/*")) {
  5329. + return true;
  5330. + }
  5331. +
  5332. + return base::MatchPattern(test, path_escaped_);
  5333. +}
  5334. +
  5335. +const std::string& URLPattern::GetAsString() const {
  5336. + if (!spec_.empty())
  5337. + return spec_;
  5338. +
  5339. + if (match_all_urls_) {
  5340. + spec_ = kAllUrlsPattern;
  5341. + return spec_;
  5342. + }
  5343. +
  5344. + bool standard_scheme = IsStandardScheme(scheme_);
  5345. +
  5346. + std::string spec = scheme_ +
  5347. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  5348. +
  5349. + if (scheme_ != url::kFileScheme && standard_scheme) {
  5350. + if (match_subdomains_) {
  5351. + spec += "*";
  5352. + if (!host_.empty())
  5353. + spec += ".";
  5354. + }
  5355. +
  5356. + if (!host_.empty())
  5357. + spec += host_;
  5358. +
  5359. + if (port_ != "*") {
  5360. + spec += ":";
  5361. + spec += port_;
  5362. + }
  5363. + }
  5364. +
  5365. + if (!path_.empty())
  5366. + spec += path_;
  5367. +
  5368. + spec_ = std::move(spec);
  5369. + return spec_;
  5370. +}
  5371. +
  5372. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  5373. + if (match_all_urls() || other.match_all_urls())
  5374. + return true;
  5375. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  5376. + other.MatchesAnyScheme(GetExplicitSchemes()))
  5377. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  5378. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  5379. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  5380. + other.MatchesPath(StripTrailingWildcard(path())));
  5381. +}
  5382. +
  5383. +bool URLPattern::Contains(const URLPattern& other) const {
  5384. + // Important: it's not enough to just check match_all_urls(); we also need to
  5385. + // make sure that the schemes in this pattern are a superset of those in
  5386. + // |other|.
  5387. + if (match_all_urls() &&
  5388. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  5389. + return true;
  5390. + }
  5391. +
  5392. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  5393. + MatchesHost(other.host()) &&
  5394. + (!other.match_subdomains_ || match_subdomains_) &&
  5395. + MatchesPortPattern(other.port()) &&
  5396. + MatchesPath(StripTrailingWildcard(other.path()));
  5397. +}
  5398. +
  5399. +absl::optional<URLPattern> URLPattern::CreateIntersection(
  5400. + const URLPattern& other) const {
  5401. + // Easy case: Schemes don't overlap. Return nullopt.
  5402. + int intersection_schemes = URLPattern::SCHEME_NONE;
  5403. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  5404. + intersection_schemes = other.valid_schemes_;
  5405. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  5406. + intersection_schemes = valid_schemes_;
  5407. + else
  5408. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  5409. +
  5410. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  5411. + return absl::nullopt;
  5412. +
  5413. + {
  5414. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  5415. + // This can happen when either:
  5416. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  5417. + // - One of the patterns has match_all_urls() equal to true.
  5418. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  5419. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  5420. + // from the path, which could yield the incorrect result.
  5421. + const URLPattern* copy_source = nullptr;
  5422. + if (*this == other || other.match_all_urls())
  5423. + copy_source = this;
  5424. + else if (match_all_urls())
  5425. + copy_source = &other;
  5426. +
  5427. + if (copy_source) {
  5428. + // NOTE: equality checks don't take into account valid_schemes_, and
  5429. + // schemes can be different in the case of match_all_urls() as well, so
  5430. + // we can't always just return *copy_source.
  5431. + if (intersection_schemes == copy_source->valid_schemes_)
  5432. + return *copy_source;
  5433. + URLPattern result(intersection_schemes);
  5434. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  5435. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  5436. + return result;
  5437. + }
  5438. + }
  5439. +
  5440. + // No more easy cases. Go through component by component to find the patterns
  5441. + // that intersect.
  5442. +
  5443. + // Note: Alias the function type (rather than using auto) because
  5444. + // MatchesHost() is overloaded.
  5445. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  5446. +
  5447. + auto get_intersection = [this, &other](base::StringPiece own_str,
  5448. + base::StringPiece other_str,
  5449. + match_function_type match_function,
  5450. + base::StringPiece* out) {
  5451. + if ((this->*match_function)(other_str)) {
  5452. + *out = other_str;
  5453. + return true;
  5454. + }
  5455. + if ((other.*match_function)(own_str)) {
  5456. + *out = own_str;
  5457. + return true;
  5458. + }
  5459. + return false;
  5460. + };
  5461. +
  5462. + base::StringPiece scheme;
  5463. + base::StringPiece host;
  5464. + base::StringPiece port;
  5465. + base::StringPiece path;
  5466. + // If any pieces fail to overlap, then there is no intersection.
  5467. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  5468. + &scheme) ||
  5469. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  5470. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  5471. + &port) ||
  5472. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  5473. + return absl::nullopt;
  5474. + }
  5475. +
  5476. + // Only match subdomains if both patterns match subdomains.
  5477. + base::StringPiece subdomains;
  5478. + if (match_subdomains_ && other.match_subdomains_) {
  5479. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  5480. + // append '*' instead of '*.'.
  5481. + subdomains = host.empty() ? "*" : "*.";
  5482. + }
  5483. +
  5484. + base::StringPiece scheme_separator =
  5485. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  5486. +
  5487. + std::string pattern_str = base::StrCat(
  5488. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  5489. +
  5490. + URLPattern pattern(intersection_schemes);
  5491. + ParseResult result = pattern.Parse(pattern_str);
  5492. + // TODO(devlin): I don't think there's any way this should ever fail, but
  5493. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  5494. + // to a DCHECK in M72.
  5495. + CHECK_EQ(ParseResult::kSuccess, result);
  5496. +
  5497. + return pattern;
  5498. +}
  5499. +
  5500. +bool URLPattern::MatchesAnyScheme(
  5501. + const std::vector<std::string>& schemes) const {
  5502. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5503. + if (MatchesScheme(*i))
  5504. + return true;
  5505. + }
  5506. +
  5507. + return false;
  5508. +}
  5509. +
  5510. +bool URLPattern::MatchesAllSchemes(
  5511. + const std::vector<std::string>& schemes) const {
  5512. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5513. + if (!MatchesScheme(*i))
  5514. + return false;
  5515. + }
  5516. +
  5517. + return true;
  5518. +}
  5519. +
  5520. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  5521. + // Ignore hostname if scheme is file://.
  5522. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  5523. + return false;
  5524. +
  5525. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  5526. + return false;
  5527. +
  5528. + return true;
  5529. +}
  5530. +
  5531. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  5532. + return port_ == "*" || port_ == port;
  5533. +}
  5534. +
  5535. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  5536. + std::vector<std::string> result;
  5537. +
  5538. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  5539. + result.push_back(scheme_);
  5540. + return result;
  5541. + }
  5542. +
  5543. + for (size_t i = 0; i < std::size(kValidSchemes); ++i) {
  5544. + if (MatchesScheme(kValidSchemes[i])) {
  5545. + result.push_back(kValidSchemes[i]);
  5546. + }
  5547. + }
  5548. +
  5549. + return result;
  5550. +}
  5551. +
  5552. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  5553. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  5554. + std::vector<URLPattern> result;
  5555. +
  5556. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  5557. + i != explicit_schemes.end(); ++i) {
  5558. + URLPattern temp = *this;
  5559. + temp.SetScheme(*i);
  5560. + temp.SetMatchAllURLs(false);
  5561. + result.push_back(temp);
  5562. + }
  5563. +
  5564. + return result;
  5565. +}
  5566. +
  5567. +// static
  5568. +const char* URLPattern::GetParseResultString(
  5569. + URLPattern::ParseResult parse_result) {
  5570. + return kParseResultMessages[static_cast<int>(parse_result)];
  5571. +}
  5572. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  5573. new file mode 100755
  5574. --- /dev/null
  5575. +++ b/components/user_scripts/common/url_pattern.h
  5576. @@ -0,0 +1,302 @@
  5577. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5578. +// Use of this source code is governed by a BSD-style license that can be
  5579. +// found in the LICENSE file.
  5580. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_H_
  5581. +#define USERSCRIPTS_COMMON_URL_PATTERN_H_
  5582. +
  5583. +#include <functional>
  5584. +#include <iosfwd>
  5585. +#include <string>
  5586. +#include <vector>
  5587. +
  5588. +#include "base/strings/string_piece.h"
  5589. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  5590. +
  5591. +class GURL;
  5592. +
  5593. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  5594. +// subset of URL syntax:
  5595. +//
  5596. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  5597. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  5598. +// 'chrome-extension' | 'filesystem'
  5599. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  5600. +// '*.' <anychar except '/' and '*'>+
  5601. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  5602. +// <path> := '/' <any chars>
  5603. +//
  5604. +// * Host is not used when the scheme is 'file'.
  5605. +// * The path can have embedded '*' characters which act as glob wildcards.
  5606. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  5607. +// a valid scheme (as specified by valid_schemes_).
  5608. +// * The '*' scheme pattern excludes file URLs.
  5609. +//
  5610. +// Examples of valid patterns:
  5611. +// - http://*/*
  5612. +// - http://*/foo*
  5613. +// - https://*.google.com/foo*bar
  5614. +// - file://monkey*
  5615. +// - http://127.0.0.1/*
  5616. +// - http://[2607:f8b0:4005:805::200e]/*
  5617. +//
  5618. +// Examples of invalid patterns:
  5619. +// - http://* -- path not specified
  5620. +// - http://*foo/bar -- * not allowed as substring of host component
  5621. +// - http://foo.*.bar/baz -- * must be first component
  5622. +// - http:/bar -- scheme separator not found
  5623. +// - foo://* -- invalid scheme
  5624. +// - chrome:// -- we don't support chrome internal URLs
  5625. +class URLPattern {
  5626. + public:
  5627. + // A collection of scheme bitmasks for use with valid_schemes.
  5628. + enum SchemeMasks {
  5629. + SCHEME_NONE = 0,
  5630. + SCHEME_HTTP = 1 << 0,
  5631. + SCHEME_HTTPS = 1 << 1,
  5632. + SCHEME_FILE = 1 << 2,
  5633. + SCHEME_FTP = 1 << 3,
  5634. + SCHEME_CHROMEUI = 1 << 4,
  5635. + SCHEME_EXTENSION = 1 << 5,
  5636. + SCHEME_FILESYSTEM = 1 << 6,
  5637. + SCHEME_WS = 1 << 7,
  5638. + SCHEME_WSS = 1 << 8,
  5639. + SCHEME_DATA = 1 << 9,
  5640. + SCHEME_URN = 1 << 10,
  5641. +
  5642. + // IMPORTANT!
  5643. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  5644. + // extension://, about:, etc. Because this has lots of security
  5645. + // implications, third-party extensions should usually not be able to get
  5646. + // access to URL patterns initialized this way. If there is a reason
  5647. + // for violating this general rule, document why this it safe.
  5648. + SCHEME_ALL = -1,
  5649. + };
  5650. +
  5651. + // Error codes returned from Parse().
  5652. + enum class ParseResult {
  5653. + kSuccess = 0,
  5654. + kMissingSchemeSeparator,
  5655. + kInvalidScheme,
  5656. + kWrongSchemeSeparator,
  5657. + kEmptyHost,
  5658. + kInvalidHostWildcard,
  5659. + kEmptyPath,
  5660. + kInvalidPort,
  5661. + kInvalidHost,
  5662. + kNumParseResults,
  5663. + };
  5664. +
  5665. + // The <all_urls> string pattern.
  5666. + static const char kAllUrlsPattern[];
  5667. +
  5668. + // Returns true if the given |scheme| is considered valid for extensions.
  5669. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  5670. +
  5671. + // Returns the mask for all schemes considered valid for extensions.
  5672. + static int GetValidSchemeMaskForExtensions();
  5673. +
  5674. + explicit URLPattern(int valid_schemes);
  5675. +
  5676. + // Convenience to construct a URLPattern from a string. If the string is not
  5677. + // known ahead of time, use Parse() instead, which returns success or failure.
  5678. + URLPattern(int valid_schemes, base::StringPiece pattern);
  5679. +
  5680. + URLPattern();
  5681. + URLPattern(const URLPattern& other);
  5682. + URLPattern(URLPattern&& other);
  5683. + ~URLPattern();
  5684. +
  5685. + URLPattern& operator=(const URLPattern& other);
  5686. + URLPattern& operator=(URLPattern&& other);
  5687. +
  5688. + bool operator<(const URLPattern& other) const;
  5689. + bool operator>(const URLPattern& other) const;
  5690. + bool operator==(const URLPattern& other) const;
  5691. +
  5692. + // Initializes this instance by parsing the provided string. Returns
  5693. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  5694. + // On failure, this instance will have some intermediate values and is in an
  5695. + // invalid state.
  5696. + ParseResult Parse(base::StringPiece pattern_str);
  5697. +
  5698. + // Gets the bitmask of valid schemes.
  5699. + int valid_schemes() const { return valid_schemes_; }
  5700. + void SetValidSchemes(int valid_schemes);
  5701. +
  5702. + // Gets the host the pattern matches. This can be an empty string if the
  5703. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  5704. + const std::string& host() const { return host_; }
  5705. + void SetHost(base::StringPiece host);
  5706. +
  5707. + // Gets whether to match subdomains of host().
  5708. + bool match_subdomains() const { return match_subdomains_; }
  5709. + void SetMatchSubdomains(bool val);
  5710. +
  5711. + // Gets the path the pattern matches with the leading slash. This can have
  5712. + // embedded asterisks which are interpreted using glob rules.
  5713. + const std::string& path() const { return path_; }
  5714. + void SetPath(base::StringPiece path);
  5715. +
  5716. + // Returns true if this pattern matches all (valid) urls.
  5717. + bool match_all_urls() const { return match_all_urls_; }
  5718. + void SetMatchAllURLs(bool val);
  5719. +
  5720. + // Sets the scheme for pattern matches. This can be a single '*' if the
  5721. + // pattern matches all valid schemes (as defined by the valid_schemes_
  5722. + // property). Returns false on failure (if the scheme is not valid).
  5723. + bool SetScheme(base::StringPiece scheme);
  5724. + // Note: You should use MatchesScheme() instead of this getter unless you
  5725. + // absolutely need the exact scheme. This is exposed for testing.
  5726. + const std::string& scheme() const { return scheme_; }
  5727. +
  5728. + // Returns true if the specified scheme can be used in this URL pattern, and
  5729. + // false otherwise. Uses valid_schemes_ to determine validity.
  5730. + bool IsValidScheme(base::StringPiece scheme) const;
  5731. +
  5732. + // Returns true if this instance matches the specified URL. Always returns
  5733. + // false for invalid URLs.
  5734. + bool MatchesURL(const GURL& test) const;
  5735. +
  5736. + // Returns true if this instance matches the specified security origin.
  5737. + bool MatchesSecurityOrigin(const GURL& test) const;
  5738. +
  5739. + // Returns true if |test| matches our scheme.
  5740. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  5741. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  5742. + // of the outer "filesystem:" part.
  5743. + bool MatchesScheme(base::StringPiece test) const;
  5744. +
  5745. + // Returns true if |test| matches our host.
  5746. + bool MatchesHost(base::StringPiece test) const;
  5747. + bool MatchesHost(const GURL& test) const;
  5748. +
  5749. + // Returns true if |test| matches our path.
  5750. + bool MatchesPath(base::StringPiece test) const;
  5751. +
  5752. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  5753. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  5754. + // matches all domains (e.g., *://*/*) will return true.
  5755. + // |private_filter| specifies whether private registries (like appspot.com)
  5756. + // should be considered; if included, patterns like *://*.appspot.com/* will
  5757. + // return true. By default, we exclude private registries (so *.appspot.com
  5758. + // returns false).
  5759. + // Note: This is an expensive method, and should be used sparingly!
  5760. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  5761. + // cached.
  5762. + bool MatchesEffectiveTld(
  5763. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  5764. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  5765. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  5766. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  5767. +
  5768. + // Returns true if the pattern only matches a single origin. The pattern may
  5769. + // include a path.
  5770. + bool MatchesSingleOrigin() const;
  5771. +
  5772. + // Sets the port. Returns false if the port is invalid.
  5773. + bool SetPort(base::StringPiece port);
  5774. + const std::string& port() const { return port_; }
  5775. +
  5776. + // Returns a string representing this instance.
  5777. + const std::string& GetAsString() const;
  5778. +
  5779. + // Determines whether there is a URL that would match this instance and
  5780. + // another instance. This method is symmetrical: Calling
  5781. + // other.OverlapsWith(this) would result in the same answer.
  5782. + bool OverlapsWith(const URLPattern& other) const;
  5783. +
  5784. + // Returns true if this pattern matches all possible URLs that |other| can
  5785. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5786. + bool Contains(const URLPattern& other) const;
  5787. +
  5788. + // Creates a new URLPattern that represents the intersection of this
  5789. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5790. + // For instance, given the patterns http://*.google.com/* and
  5791. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5792. + // NOTES:
  5793. + // - Though scheme intersections are supported, the serialization of
  5794. + // URLPatternSet does not record them. Be sure that this is safe for your
  5795. + // use cases.
  5796. + // - Path intersection is done on a best-effort basis. If one path clearly
  5797. + // contains another, it will be handled correctly, but this method does not
  5798. + // deal with cases like /*a* and /*b* (where technically the intersection
  5799. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5800. + absl::optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5801. +
  5802. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5803. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5804. + // wildcard scheme, then the returned set will contain one element that is
  5805. + // equivalent to this instance.
  5806. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5807. +
  5808. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5809. + if (a.match_all_urls_ && b.match_all_urls_)
  5810. + return false;
  5811. + return a.host_.compare(b.host_) < 0;
  5812. + }
  5813. +
  5814. + // Used for origin comparisons in a std::set.
  5815. + class EffectiveHostCompareFunctor {
  5816. + public:
  5817. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5818. + return EffectiveHostCompare(a, b);
  5819. + }
  5820. + };
  5821. +
  5822. + // Get an error string for a ParseResult.
  5823. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5824. +
  5825. + private:
  5826. + // Returns true if any of the |schemes| items matches our scheme.
  5827. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5828. +
  5829. + // Returns true if all of the |schemes| items matches our scheme.
  5830. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5831. +
  5832. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5833. +
  5834. + // Returns true if our port matches the |port| pattern (it may be "*").
  5835. + bool MatchesPortPattern(base::StringPiece port) const;
  5836. +
  5837. + // If the URLPattern contains a wildcard scheme, returns a list of
  5838. + // equivalent literal schemes, otherwise returns the current scheme.
  5839. + std::vector<std::string> GetExplicitSchemes() const;
  5840. +
  5841. + // A bitmask containing the schemes which are considered valid for this
  5842. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5843. + // scheme.
  5844. + int valid_schemes_;
  5845. +
  5846. + // True if this is a special-case "<all_urls>" pattern.
  5847. + bool match_all_urls_;
  5848. +
  5849. + // The scheme for the pattern.
  5850. + std::string scheme_;
  5851. +
  5852. + // The host without any leading "*" components.
  5853. + std::string host_;
  5854. +
  5855. + // Whether we should match subdomains of the host. This is true if the first
  5856. + // component of the pattern's host was "*".
  5857. + bool match_subdomains_;
  5858. +
  5859. + // The port.
  5860. + std::string port_;
  5861. +
  5862. + // The path to match. This is everything after the host of the URL, or
  5863. + // everything after the scheme in the case of file:// URLs.
  5864. + std::string path_;
  5865. +
  5866. + // The path with "?" and "\" characters escaped for use with the
  5867. + // MatchPattern() function.
  5868. + std::string path_escaped_;
  5869. +
  5870. + // A string representing this URLPattern.
  5871. + mutable std::string spec_;
  5872. +};
  5873. +
  5874. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5875. +
  5876. +typedef std::vector<URLPattern> URLPatternList;
  5877. +
  5878. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_H_
  5879. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5880. new file mode 100755
  5881. --- /dev/null
  5882. +++ b/components/user_scripts/common/url_pattern_set.cc
  5883. @@ -0,0 +1,335 @@
  5884. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5885. +// Use of this source code is governed by a BSD-style license that can be
  5886. +// found in the LICENSE file.
  5887. +
  5888. +#include "url_pattern_set.h"
  5889. +
  5890. +#include <iterator>
  5891. +#include <ostream>
  5892. +
  5893. +#include "base/containers/contains.h"
  5894. +#include "base/logging.h"
  5895. +#include "base/stl_util.h"
  5896. +#include "base/values.h"
  5897. +#include "error_utils.h"
  5898. +#include "url_pattern.h"
  5899. +#include "url/gurl.h"
  5900. +#include "url/origin.h"
  5901. +#include "url/url_constants.h"
  5902. +#include "user_scripts_features.h"
  5903. +
  5904. +namespace user_scripts {
  5905. +
  5906. +namespace {
  5907. +
  5908. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5909. +
  5910. +} // namespace
  5911. +
  5912. +// static
  5913. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5914. + const URLPatternSet& set2) {
  5915. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5916. + set1.patterns_, set2.patterns_));
  5917. +}
  5918. +
  5919. +// static
  5920. +URLPatternSet URLPatternSet::CreateIntersection(
  5921. + const URLPatternSet& set1,
  5922. + const URLPatternSet& set2,
  5923. + IntersectionBehavior intersection_behavior) {
  5924. + // Note: leverage return value optimization; always return the same object.
  5925. + URLPatternSet result;
  5926. +
  5927. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5928. + // String comparison just relies on STL set behavior, which looks at the
  5929. + // string representation.
  5930. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5931. + set1.patterns_, set2.patterns_));
  5932. + return result;
  5933. + }
  5934. +
  5935. + // Look for a semantic intersection.
  5936. +
  5937. + // Step 1: Iterate over each set. Find any patterns that are completely
  5938. + // contained by the other (thus being necessarily present in any intersection)
  5939. + // and add them, collecting the others in a set of unique items.
  5940. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5941. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5942. + // const, this should be safe.
  5943. + std::vector<const URLPattern*> unique_set1;
  5944. + for (const URLPattern& pattern : set1) {
  5945. + if (set2.ContainsPattern(pattern))
  5946. + result.patterns_.insert(pattern);
  5947. + else
  5948. + unique_set1.push_back(&pattern);
  5949. + }
  5950. + std::vector<const URLPattern*> unique_set2;
  5951. + for (const URLPattern& pattern : set2) {
  5952. + if (set1.ContainsPattern(pattern))
  5953. + result.patterns_.insert(pattern);
  5954. + else
  5955. + unique_set2.push_back(&pattern);
  5956. + }
  5957. +
  5958. + // If we're just looking for patterns contained by both, we're done.
  5959. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5960. + return result;
  5961. +
  5962. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5963. +
  5964. + // Step 2: Iterate over all the unique patterns and find the intersections
  5965. + // they have with the other patterns.
  5966. + for (const auto* pattern : unique_set1) {
  5967. + for (const auto* pattern2 : unique_set2) {
  5968. + absl::optional<URLPattern> intersection =
  5969. + pattern->CreateIntersection(*pattern2);
  5970. + if (intersection)
  5971. + result.patterns_.insert(std::move(*intersection));
  5972. + }
  5973. + }
  5974. +
  5975. + return result;
  5976. +}
  5977. +
  5978. +// static
  5979. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  5980. + const URLPatternSet& set2) {
  5981. + return URLPatternSet(
  5982. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  5983. +}
  5984. +
  5985. +// static
  5986. +URLPatternSet URLPatternSet::CreateUnion(
  5987. + const std::vector<URLPatternSet>& sets) {
  5988. + URLPatternSet result;
  5989. + if (sets.empty())
  5990. + return result;
  5991. +
  5992. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  5993. + //
  5994. + // Do the first merge step into a working set so that we don't mutate any of
  5995. + // the input.
  5996. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  5997. + // clean that up.
  5998. + std::vector<URLPatternSet> working;
  5999. + for (size_t i = 0; i < sets.size(); i += 2) {
  6000. + if (i + 1 < sets.size())
  6001. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  6002. + else
  6003. + working.push_back(sets[i].Clone());
  6004. + }
  6005. +
  6006. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  6007. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  6008. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  6009. + working[i].patterns_.swap(u.patterns_);
  6010. + }
  6011. + }
  6012. +
  6013. + result.patterns_.swap(working[0].patterns_);
  6014. + return result;
  6015. +}
  6016. +
  6017. +URLPatternSet::URLPatternSet() = default;
  6018. +
  6019. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  6020. +
  6021. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  6022. + : patterns_(patterns) {}
  6023. +
  6024. +URLPatternSet::~URLPatternSet() = default;
  6025. +
  6026. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  6027. +
  6028. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  6029. + return patterns_ == other.patterns_;
  6030. +}
  6031. +
  6032. +std::ostream& operator<<(std::ostream& out,
  6033. + const URLPatternSet& url_pattern_set) {
  6034. + out << "{ ";
  6035. +
  6036. + auto iter = url_pattern_set.patterns().cbegin();
  6037. + if (!url_pattern_set.patterns().empty()) {
  6038. + out << *iter;
  6039. + ++iter;
  6040. + }
  6041. +
  6042. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  6043. + out << ", " << *iter;
  6044. +
  6045. + if (!url_pattern_set.patterns().empty())
  6046. + out << " ";
  6047. +
  6048. + out << "}";
  6049. + return out;
  6050. +}
  6051. +
  6052. +URLPatternSet URLPatternSet::Clone() const {
  6053. + return URLPatternSet(patterns_);
  6054. +}
  6055. +
  6056. +bool URLPatternSet::is_empty() const {
  6057. + return patterns_.empty();
  6058. +}
  6059. +
  6060. +size_t URLPatternSet::size() const {
  6061. + return patterns_.size();
  6062. +}
  6063. +
  6064. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  6065. + return patterns_.insert(pattern).second;
  6066. +}
  6067. +
  6068. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  6069. + patterns_.insert(set.patterns().begin(),
  6070. + set.patterns().end());
  6071. +}
  6072. +
  6073. +void URLPatternSet::ClearPatterns() {
  6074. + patterns_.clear();
  6075. +}
  6076. +
  6077. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  6078. + if (origin.is_empty())
  6079. + return false;
  6080. + const url::Origin real_origin = url::Origin::Create(origin);
  6081. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(
  6082. + origin.DeprecatedGetOriginAsURL())));
  6083. + URLPattern origin_pattern(valid_schemes);
  6084. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  6085. + if (origin_pattern.Parse(origin.spec()) !=
  6086. + URLPattern::ParseResult::kSuccess) {
  6087. + return false;
  6088. + }
  6089. + origin_pattern.SetPath("/*");
  6090. + return AddPattern(origin_pattern);
  6091. +}
  6092. +
  6093. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  6094. + for (auto it = other.begin(); it != other.end(); ++it) {
  6095. + if (!ContainsPattern(*it))
  6096. + return false;
  6097. + }
  6098. +
  6099. + return true;
  6100. +}
  6101. +
  6102. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  6103. + for (auto it = begin(); it != end(); ++it) {
  6104. + if (it->Contains(pattern))
  6105. + return true;
  6106. + }
  6107. + return false;
  6108. +}
  6109. +
  6110. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  6111. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  6112. + ++pattern) {
  6113. + if (pattern->MatchesURL(url)) {
  6114. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6115. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  6116. +
  6117. + return true;
  6118. + }
  6119. + }
  6120. +
  6121. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6122. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  6123. +
  6124. + return false;
  6125. +}
  6126. +
  6127. +bool URLPatternSet::MatchesAllURLs() const {
  6128. + for (auto host = begin(); host != end(); ++host) {
  6129. + if (host->match_all_urls() ||
  6130. + (host->match_subdomains() && host->host().empty()))
  6131. + return true;
  6132. + }
  6133. + return false;
  6134. +}
  6135. +
  6136. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  6137. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  6138. + ++pattern) {
  6139. + if (pattern->MatchesSecurityOrigin(origin))
  6140. + return true;
  6141. + }
  6142. +
  6143. + return false;
  6144. +}
  6145. +
  6146. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  6147. + // Two extension extents overlap if there is any one URL that would match at
  6148. + // least one pattern in each of the extents.
  6149. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6150. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  6151. + ++j) {
  6152. + if (i->OverlapsWith(*j))
  6153. + return true;
  6154. + }
  6155. + }
  6156. +
  6157. + return false;
  6158. +}
  6159. +
  6160. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  6161. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  6162. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6163. + base::Value pattern_str_value(i->GetAsString());
  6164. + if (!base::Contains(value->GetList(), pattern_str_value))
  6165. + value->Append(std::move(pattern_str_value));
  6166. + }
  6167. + return value;
  6168. +}
  6169. +
  6170. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  6171. + int valid_schemes,
  6172. + bool allow_file_access,
  6173. + std::string* error) {
  6174. + ClearPatterns();
  6175. + for (size_t i = 0; i < patterns.size(); ++i) {
  6176. + URLPattern pattern(valid_schemes);
  6177. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  6178. + if (error) {
  6179. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  6180. + patterns[i]);
  6181. + } else {
  6182. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  6183. + }
  6184. + return false;
  6185. + }
  6186. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  6187. + pattern.SetValidSchemes(
  6188. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  6189. + }
  6190. + AddPattern(pattern);
  6191. + }
  6192. + return true;
  6193. +}
  6194. +
  6195. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  6196. + const {
  6197. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  6198. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6199. + value->push_back(i->GetAsString());
  6200. + }
  6201. + return value;
  6202. +}
  6203. +
  6204. +bool URLPatternSet::Populate(const base::ListValue& value,
  6205. + int valid_schemes,
  6206. + bool allow_file_access,
  6207. + std::string* error) {
  6208. + std::vector<std::string> patterns;
  6209. + for (const base::Value& pattern : value.GetList()) {
  6210. + const std::string* item = pattern.GetIfString();
  6211. + if (!item)
  6212. + return false;
  6213. + patterns.push_back(*item);
  6214. + }
  6215. + return Populate(patterns, valid_schemes, allow_file_access, error);
  6216. +}
  6217. +
  6218. +} // namespace extensions
  6219. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  6220. new file mode 100755
  6221. --- /dev/null
  6222. +++ b/components/user_scripts/common/url_pattern_set.h
  6223. @@ -0,0 +1,160 @@
  6224. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6225. +// Use of this source code is governed by a BSD-style license that can be
  6226. +// found in the LICENSE file.
  6227. +
  6228. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6229. +#define USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6230. +
  6231. +#include <stddef.h>
  6232. +
  6233. +#include <iosfwd>
  6234. +#include <memory>
  6235. +#include <set>
  6236. +
  6237. +#include "url_pattern.h"
  6238. +
  6239. +class GURL;
  6240. +
  6241. +namespace base {
  6242. +class ListValue;
  6243. +class Value;
  6244. +}
  6245. +
  6246. +namespace user_scripts {
  6247. +
  6248. +// Represents the set of URLs an extension uses for web content.
  6249. +class URLPatternSet {
  6250. + public:
  6251. + URLPatternSet(const URLPatternSet&) = delete;
  6252. + URLPatternSet& operator=(const URLPatternSet&) = delete;
  6253. + typedef std::set<URLPattern>::const_iterator const_iterator;
  6254. + typedef std::set<URLPattern>::iterator iterator;
  6255. +
  6256. + // Returns |set1| - |set2|.
  6257. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  6258. + const URLPatternSet& set2);
  6259. +
  6260. + enum class IntersectionBehavior {
  6261. + // For the following descriptions, consider the two URLPatternSets:
  6262. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  6263. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  6264. + // "*://chromium.org/*"}
  6265. +
  6266. + // Only includes patterns that are exactly in both sets. The intersection of
  6267. + // the two sets above is {"https://example.com/*"}, since that is the only
  6268. + // pattern that appears exactly in each.
  6269. + kStringComparison,
  6270. +
  6271. + // Includes patterns that are effectively contained by both sets. The
  6272. + // intersection of the two sets above is
  6273. + // {
  6274. + // "https://example.com/*" (contained exactly by each set)
  6275. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6276. + // subset of https://*.google.com/* in set 1)
  6277. + // }
  6278. + kPatternsContainedByBoth,
  6279. +
  6280. + // Includes patterns that are contained by both sets and creates new
  6281. + // patterns to represent the intersection of any others. The intersection of
  6282. + // the two sets above is
  6283. + // {
  6284. + // "https://example.com/*" (contained exactly by each set)
  6285. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6286. + // subset of https://*.google.com/* in set 1)
  6287. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  6288. + // *://chromium.org/*" in set 2).
  6289. + // }
  6290. + // Note that this is the most computationally expensive - potentially
  6291. + // O(n^2) - since it can require comparing each pattern in one set to every
  6292. + // pattern in the other set.
  6293. + kDetailed,
  6294. + };
  6295. +
  6296. + // Returns the intersection of |set1| and |set2| according to
  6297. + // |intersection_behavior|.
  6298. + static URLPatternSet CreateIntersection(
  6299. + const URLPatternSet& set1,
  6300. + const URLPatternSet& set2,
  6301. + IntersectionBehavior intersection_behavior);
  6302. +
  6303. + // Returns the union of |set1| and |set2|.
  6304. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  6305. + const URLPatternSet& set2);
  6306. +
  6307. + // Returns the union of all sets in |sets|.
  6308. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  6309. +
  6310. + URLPatternSet();
  6311. + URLPatternSet(URLPatternSet&& rhs);
  6312. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  6313. + ~URLPatternSet();
  6314. +
  6315. + URLPatternSet& operator=(URLPatternSet&& rhs);
  6316. + bool operator==(const URLPatternSet& rhs) const;
  6317. +
  6318. + bool is_empty() const;
  6319. + size_t size() const;
  6320. + const std::set<URLPattern>& patterns() const { return patterns_; }
  6321. + const_iterator begin() const { return patterns_.begin(); }
  6322. + const_iterator end() const { return patterns_.end(); }
  6323. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  6324. +
  6325. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  6326. + // constructor to avoid accidental/unnecessary copies.
  6327. + URLPatternSet Clone() const;
  6328. +
  6329. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  6330. + // false if the pattern was already in the set.
  6331. + bool AddPattern(const URLPattern& pattern);
  6332. +
  6333. + // Adds all patterns from |set| into this.
  6334. + void AddPatterns(const URLPatternSet& set);
  6335. +
  6336. + void ClearPatterns();
  6337. +
  6338. + // Adds a pattern based on |origin| to the set.
  6339. + bool AddOrigin(int valid_schemes, const GURL& origin);
  6340. +
  6341. + // Returns true if every URL that matches |set| is matched by this. In other
  6342. + // words, if every pattern in |set| is encompassed by a pattern in this.
  6343. + bool Contains(const URLPatternSet& set) const;
  6344. +
  6345. + // Returns true if any pattern in this set encompasses |pattern|.
  6346. + bool ContainsPattern(const URLPattern& pattern) const;
  6347. +
  6348. + // Test if the extent contains a URL.
  6349. + bool MatchesURL(const GURL& url) const;
  6350. +
  6351. + // Test if the extent matches all URLs (for example, <all_urls>).
  6352. + bool MatchesAllURLs() const;
  6353. +
  6354. + bool MatchesSecurityOrigin(const GURL& origin) const;
  6355. +
  6356. + // Returns true if there is a single URL that would be in two extents.
  6357. + bool OverlapsWith(const URLPatternSet& other) const;
  6358. +
  6359. + // Converts to and from Value for serialization to preferences.
  6360. + std::unique_ptr<base::ListValue> ToValue() const;
  6361. + bool Populate(const base::ListValue& value,
  6362. + int valid_schemes,
  6363. + bool allow_file_access,
  6364. + std::string* error);
  6365. +
  6366. + // Converts to and from a vector of strings.
  6367. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  6368. + bool Populate(const std::vector<std::string>& patterns,
  6369. + int valid_schemes,
  6370. + bool allow_file_access,
  6371. + std::string* error);
  6372. +
  6373. + private:
  6374. + // The list of URL patterns that comprise the extent.
  6375. + std::set<URLPattern> patterns_;
  6376. +};
  6377. +
  6378. +std::ostream& operator<<(std::ostream& out,
  6379. + const URLPatternSet& url_pattern_set);
  6380. +
  6381. +} // namespace extensions
  6382. +
  6383. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6384. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  6385. new file mode 100755
  6386. --- /dev/null
  6387. +++ b/components/user_scripts/common/user_script.cc
  6388. @@ -0,0 +1,329 @@
  6389. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6390. +// Use of this source code is governed by a BSD-style license that can be
  6391. +// found in the LICENSE file.
  6392. +
  6393. +#include "user_script.h"
  6394. +
  6395. +#include <stddef.h>
  6396. +#include <stdint.h>
  6397. +
  6398. +#include <memory>
  6399. +#include <utility>
  6400. +
  6401. +#include "base/atomic_sequence_num.h"
  6402. +#include "base/command_line.h"
  6403. +#include "base/pickle.h"
  6404. +#include "base/strings/pattern.h"
  6405. +#include "base/strings/string_util.h"
  6406. +#include "user_scripts_features.h"
  6407. +
  6408. +namespace {
  6409. +
  6410. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  6411. +// from multiple threads.
  6412. +base::AtomicSequenceNumber g_user_script_id_generator;
  6413. +
  6414. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  6415. + const GURL& url) {
  6416. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  6417. + if (base::MatchPattern(url.spec(), *glob))
  6418. + return true;
  6419. + }
  6420. +
  6421. + return false;
  6422. +}
  6423. +
  6424. +} // namespace
  6425. +
  6426. +namespace user_scripts {
  6427. +
  6428. +// The bitmask for valid user script injectable schemes used by URLPattern.
  6429. +enum {
  6430. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  6431. + URLPattern::SCHEME_HTTP |
  6432. + URLPattern::SCHEME_HTTPS
  6433. + //| URLPattern::SCHEME_FILE |
  6434. + //URLPattern::SCHEME_FTP
  6435. +};
  6436. +
  6437. +// static
  6438. +const char UserScript::kFileExtension[] = ".user.js";
  6439. +
  6440. +// static
  6441. +int UserScript::GenerateUserScriptID() {
  6442. + return g_user_script_id_generator.GetNext();
  6443. +}
  6444. +
  6445. +bool UserScript::IsURLUserScript(const GURL& url,
  6446. + const std::string& mime_type) {
  6447. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  6448. + base::CompareCase::INSENSITIVE_ASCII) &&
  6449. + mime_type != "text/html";
  6450. +}
  6451. +
  6452. +// static
  6453. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  6454. + if (canExecuteScriptEverywhere)
  6455. + return URLPattern::SCHEME_ALL;
  6456. + int valid_schemes = kValidUserScriptSchemes;
  6457. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  6458. + // switches::kExtensionsOnChromeURLs)) {
  6459. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  6460. + // }
  6461. + return valid_schemes;
  6462. +}
  6463. +
  6464. +UserScript::File::File(const base::FilePath& extension_root,
  6465. + const base::FilePath& relative_path,
  6466. + const GURL& url)
  6467. + : extension_root_(extension_root),
  6468. + relative_path_(relative_path),
  6469. + url_(url) {
  6470. +}
  6471. +
  6472. +UserScript::File::File() {}
  6473. +
  6474. +UserScript::File::File(const File& other)
  6475. + : extension_root_(other.extension_root_),
  6476. + relative_path_(other.relative_path_),
  6477. + url_(other.url_),
  6478. + external_content_(other.external_content_),
  6479. + content_(other.content_),
  6480. + key_(other.key_) {}
  6481. +
  6482. +UserScript::File::~File() {}
  6483. +
  6484. +UserScript::UserScript() = default;
  6485. +UserScript::~UserScript() = default;
  6486. +
  6487. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  6488. + url_set_.AddPattern(pattern);
  6489. +}
  6490. +
  6491. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  6492. + exclude_url_set_.AddPattern(pattern);
  6493. +}
  6494. +
  6495. +bool UserScript::MatchesURL(const GURL& url) const {
  6496. + // Since the injecton is also provided for native pages,
  6497. + // we must verify that the render process does not include
  6498. + // scripts in the schema that are not allowed
  6499. +
  6500. + // we allow only URLPattern::SCHEME_HTTP(S)
  6501. + URLPattern pattern(kValidUserScriptSchemes);
  6502. + pattern.Parse(url.spec());
  6503. + if (!pattern.IsValidScheme(pattern.scheme()))
  6504. + return false;
  6505. +
  6506. + if (!url_set_.is_empty()) {
  6507. + if (!url_set_.MatchesURL(url)) {
  6508. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6509. + LOG(INFO) << "UserScripts: No Match for url_set";
  6510. + return false;
  6511. + }
  6512. + }
  6513. +
  6514. + if (!exclude_url_set_.is_empty()) {
  6515. + if (exclude_url_set_.MatchesURL(url)) {
  6516. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6517. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  6518. + return false;
  6519. + }
  6520. + }
  6521. +
  6522. + if (!globs_.empty()) {
  6523. + if (!UrlMatchesGlobs(&globs_, url)) {
  6524. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6525. + LOG(INFO) << "UserScripts: No Match for globs";
  6526. + return false;
  6527. + }
  6528. + }
  6529. +
  6530. + if (!exclude_globs_.empty()) {
  6531. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  6532. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6533. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  6534. + return false;
  6535. + }
  6536. + }
  6537. +
  6538. + return true;
  6539. +}
  6540. +
  6541. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  6542. + bool is_subframe) const {
  6543. + if (is_subframe && !match_all_frames())
  6544. + return false;
  6545. +
  6546. + return MatchesURL(effective_document_url);
  6547. +}
  6548. +
  6549. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  6550. + pickle->WriteString(url_.spec());
  6551. + // Do not write path. It's not needed in the renderer.
  6552. + // Do not write content. It will be serialized by other means.
  6553. +}
  6554. +
  6555. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  6556. + base::PickleIterator* iter) {
  6557. + // Read the url from the pickle.
  6558. + std::string url;
  6559. + CHECK(iter->ReadString(&url));
  6560. + set_url(GURL(url));
  6561. +}
  6562. +
  6563. +void UserScript::Pickle(base::Pickle* pickle) const {
  6564. + // Write the simple types to the pickle.
  6565. + pickle->WriteInt(run_location());
  6566. + pickle->WriteInt(user_script_id_);
  6567. + pickle->WriteString(name_);
  6568. + pickle->WriteBool(emulate_greasemonkey());
  6569. + pickle->WriteBool(match_all_frames());
  6570. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  6571. + pickle->WriteBool(is_incognito_enabled());
  6572. +
  6573. + PickleHostID(pickle, host_id_);
  6574. + pickle->WriteInt(consumer_instance_type());
  6575. + PickleGlobs(pickle, globs_);
  6576. + PickleGlobs(pickle, exclude_globs_);
  6577. + PickleURLPatternSet(pickle, url_set_);
  6578. + PickleURLPatternSet(pickle, exclude_url_set_);
  6579. + PickleScripts(pickle, js_scripts_);
  6580. + PickleScripts(pickle, css_scripts_);
  6581. +}
  6582. +
  6583. +void UserScript::PickleGlobs(base::Pickle* pickle,
  6584. + const std::vector<std::string>& globs) const {
  6585. + pickle->WriteUInt32(globs.size());
  6586. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  6587. + pickle->WriteString(*glob);
  6588. + }
  6589. +}
  6590. +
  6591. +void UserScript::PickleHostID(base::Pickle* pickle,
  6592. + const HostID& host_id) const {
  6593. + pickle->WriteInt(host_id.type());
  6594. + pickle->WriteString(host_id.id());
  6595. +}
  6596. +
  6597. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  6598. + const URLPatternSet& pattern_list) const {
  6599. + pickle->WriteUInt32(pattern_list.patterns().size());
  6600. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  6601. + ++pattern) {
  6602. + pickle->WriteInt(pattern->valid_schemes());
  6603. + pickle->WriteString(pattern->GetAsString());
  6604. + }
  6605. +}
  6606. +
  6607. +void UserScript::PickleScripts(base::Pickle* pickle,
  6608. + const FileList& scripts) const {
  6609. + pickle->WriteUInt32(scripts.size());
  6610. + for (const std::unique_ptr<File>& file : scripts)
  6611. + file->Pickle(pickle);
  6612. +}
  6613. +
  6614. +void UserScript::Unpickle(const base::Pickle& pickle,
  6615. + base::PickleIterator* iter) {
  6616. + // Read the run location.
  6617. + int run_location = 0;
  6618. + CHECK(iter->ReadInt(&run_location));
  6619. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  6620. + run_location_ = static_cast<RunLocation>(run_location);
  6621. +
  6622. + CHECK(iter->ReadInt(&user_script_id_));
  6623. + CHECK(iter->ReadString(&name_));
  6624. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  6625. + CHECK(iter->ReadBool(&match_all_frames_));
  6626. + int match_origin_as_fallback_int = 0;
  6627. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  6628. + match_origin_as_fallback_ =
  6629. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  6630. + CHECK(iter->ReadBool(&incognito_enabled_));
  6631. +
  6632. + UnpickleHostID(pickle, iter, &host_id_);
  6633. +
  6634. + int consumer_instance_type = 0;
  6635. + CHECK(iter->ReadInt(&consumer_instance_type));
  6636. + consumer_instance_type_ =
  6637. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  6638. +
  6639. + UnpickleGlobs(pickle, iter, &globs_);
  6640. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  6641. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  6642. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  6643. + UnpickleScripts(pickle, iter, &js_scripts_);
  6644. + UnpickleScripts(pickle, iter, &css_scripts_);
  6645. +}
  6646. +
  6647. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  6648. + base::PickleIterator* iter,
  6649. + std::vector<std::string>* globs) {
  6650. + uint32_t num_globs = 0;
  6651. + CHECK(iter->ReadUInt32(&num_globs));
  6652. + globs->clear();
  6653. + for (uint32_t i = 0; i < num_globs; ++i) {
  6654. + std::string glob;
  6655. + CHECK(iter->ReadString(&glob));
  6656. + globs->push_back(glob);
  6657. + }
  6658. +}
  6659. +
  6660. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  6661. + base::PickleIterator* iter,
  6662. + HostID* host_id) {
  6663. + int type = 0;
  6664. + std::string id;
  6665. + CHECK(iter->ReadInt(&type));
  6666. + CHECK(iter->ReadString(&id));
  6667. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  6668. +}
  6669. +
  6670. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  6671. + base::PickleIterator* iter,
  6672. + URLPatternSet* pattern_list) {
  6673. + uint32_t num_patterns = 0;
  6674. + CHECK(iter->ReadUInt32(&num_patterns));
  6675. +
  6676. + pattern_list->ClearPatterns();
  6677. + for (uint32_t i = 0; i < num_patterns; ++i) {
  6678. + int valid_schemes;
  6679. + CHECK(iter->ReadInt(&valid_schemes));
  6680. +
  6681. + std::string pattern_str;
  6682. + CHECK(iter->ReadString(&pattern_str));
  6683. +
  6684. + URLPattern pattern(kValidUserScriptSchemes);
  6685. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  6686. + CHECK(URLPattern::ParseResult::kSuccess == result)
  6687. + << URLPattern::GetParseResultString(result) << " "
  6688. + << pattern_str.c_str();
  6689. +
  6690. + pattern.SetValidSchemes(valid_schemes);
  6691. + pattern_list->AddPattern(pattern);
  6692. + }
  6693. +}
  6694. +
  6695. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  6696. + base::PickleIterator* iter,
  6697. + FileList* scripts) {
  6698. + uint32_t num_files = 0;
  6699. + CHECK(iter->ReadUInt32(&num_files));
  6700. + scripts->clear();
  6701. + for (uint32_t i = 0; i < num_files; ++i) {
  6702. + std::unique_ptr<File> file(new File());
  6703. + file->Unpickle(pickle, iter);
  6704. + scripts->push_back(std::move(file));
  6705. + }
  6706. +}
  6707. +
  6708. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  6709. + : id(id), host_id(host_id) {}
  6710. +
  6711. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  6712. +
  6713. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  6714. + return a.id < b.id;
  6715. +}
  6716. +
  6717. +} // namespace extensions
  6718. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  6719. new file mode 100755
  6720. --- /dev/null
  6721. +++ b/components/user_scripts/common/user_script.h
  6722. @@ -0,0 +1,403 @@
  6723. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6724. +// Use of this source code is governed by a BSD-style license that can be
  6725. +// found in the LICENSE file.
  6726. +
  6727. +#ifndef USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6728. +#define USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6729. +
  6730. +#include <memory>
  6731. +#include <string>
  6732. +#include <vector>
  6733. +
  6734. +#include "base/files/file_path.h"
  6735. +#include "base/strings/string_piece.h"
  6736. +#include "script_constants.h"
  6737. +#include "host_id.h"
  6738. +#include "url_pattern.h"
  6739. +#include "url_pattern_set.h"
  6740. +#include "url/gurl.h"
  6741. +
  6742. +namespace base {
  6743. +class Pickle;
  6744. +class PickleIterator;
  6745. +}
  6746. +
  6747. +namespace user_scripts {
  6748. +
  6749. +// Represents a user script, either a standalone one, or one that is part of an
  6750. +// extension.
  6751. +class UserScript {
  6752. + public:
  6753. + UserScript(const UserScript&) = delete;
  6754. + UserScript& operator=(const UserScript&) = delete;
  6755. + // The file extension for standalone user scripts.
  6756. + static const char kFileExtension[];
  6757. +
  6758. + static int GenerateUserScriptID();
  6759. +
  6760. + // Check if a URL should be treated as a user script and converted to an
  6761. + // extension.
  6762. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  6763. +
  6764. + // Get the valid user script schemes for the current process. If
  6765. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6766. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6767. +
  6768. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6769. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6770. + // The type of injected script.
  6771. + enum InjectionType {
  6772. + // A content script specified in the extension's manifest.
  6773. + CONTENT_SCRIPT,
  6774. + // A script injected via, e.g. tabs.executeScript().
  6775. + //PROGRAMMATIC_SCRIPT
  6776. + };
  6777. + // The last type of injected script; used for enum verification in IPC.
  6778. + // Update this if you add more injected script types!
  6779. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6780. +
  6781. + // Locations that user scripts can be run inside the document.
  6782. + // The three run locations must strictly follow each other in both load order
  6783. + // (i.e., start *always* comes before end) and numerically, as we use
  6784. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6785. + enum RunLocation {
  6786. + UNDEFINED,
  6787. + DOCUMENT_START, // After the documentElement is created, but before
  6788. + // anything else happens.
  6789. + DOCUMENT_END, // After the entire document is parsed. Same as
  6790. + // DOMContentLoaded.
  6791. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6792. + // is "idle". Currently this uses the simple heuristic of:
  6793. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6794. + // particular injection point is guaranteed.
  6795. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6796. + // reasons, and was executed at a later time.
  6797. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6798. + // IPC in the browser process.
  6799. + RUN_LOCATION_LAST // Leave this as the last item.
  6800. + };
  6801. +
  6802. + // Holds script file info.
  6803. + class File {
  6804. + public:
  6805. + File(const base::FilePath& extension_root,
  6806. + const base::FilePath& relative_path,
  6807. + const GURL& url);
  6808. + File();
  6809. + File(const File& other);
  6810. + ~File();
  6811. +
  6812. + const base::FilePath& extension_root() const { return extension_root_; }
  6813. + const base::FilePath& relative_path() const { return relative_path_; }
  6814. +
  6815. + const GURL& url() const { return url_; }
  6816. + void set_url(const GURL& url) { url_ = url; }
  6817. +
  6818. + // If external_content_ is set returns it as content otherwise it returns
  6819. + // content_
  6820. + const base::StringPiece GetContent() const {
  6821. + if (external_content_.data())
  6822. + return external_content_;
  6823. + else
  6824. + return content_;
  6825. + }
  6826. + void set_external_content(const base::StringPiece& content) {
  6827. + external_content_ = content;
  6828. + }
  6829. + void set_content(const base::StringPiece& content) {
  6830. + content_.assign(content.begin(), content.end());
  6831. + }
  6832. +
  6833. + const std::string& key() const { return key_; }
  6834. + void set_key(const std::string& key) {
  6835. + key_ = key;
  6836. + }
  6837. +
  6838. + // Serialization support. The content and FilePath members will not be
  6839. + // serialized!
  6840. + void Pickle(base::Pickle* pickle) const;
  6841. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6842. +
  6843. + private:
  6844. + // Where the script file lives on the disk. We keep the path split so that
  6845. + // it can be localized at will.
  6846. + base::FilePath extension_root_;
  6847. + base::FilePath relative_path_;
  6848. +
  6849. + // The url to this script file.
  6850. + GURL url_;
  6851. +
  6852. + // The script content. It can be set to either loaded_content_ or
  6853. + // externally allocated string.
  6854. + base::StringPiece external_content_;
  6855. +
  6856. + // Set when the content is loaded by LoadContent
  6857. + std::string content_;
  6858. +
  6859. + std::string key_;
  6860. + };
  6861. +
  6862. + using FileList = std::vector<std::unique_ptr<File>>;
  6863. +
  6864. + // Type of a API consumer instance that user scripts will be injected on.
  6865. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6866. +
  6867. + // Constructor. Default the run location to document end, which is like
  6868. + // Greasemonkey and probably more useful for typical scripts.
  6869. + UserScript();
  6870. + ~UserScript();
  6871. +
  6872. + // Performs a copy of all fields except file contents.
  6873. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6874. +
  6875. + const std::string& name_space() const { return name_space_; }
  6876. + void set_name_space(const std::string& name_space) {
  6877. + name_space_ = name_space;
  6878. + }
  6879. +
  6880. + const std::string& name() const { return name_; }
  6881. + void set_name(const std::string& name) { name_ = name; }
  6882. +
  6883. + const std::string& version() const { return version_; }
  6884. + void set_version(const std::string& version) {
  6885. + version_ = version;
  6886. + }
  6887. +
  6888. + const std::string& key() const { return key_; }
  6889. + void set_key(const std::string& key) {
  6890. + key_ = key;
  6891. + }
  6892. +
  6893. + const std::string& file_path() const { return file_path_; }
  6894. + void set_file_path(const std::string& file_path) {
  6895. + file_path_ = file_path;
  6896. + }
  6897. +
  6898. + const std::string& url_source() const { return url_source_; }
  6899. + void set_url_source(const std::string& url_source) {
  6900. + url_source_ = url_source;
  6901. + }
  6902. +
  6903. + const std::string& description() const { return description_; }
  6904. + void set_description(const std::string& description) {
  6905. + description_ = description;
  6906. + }
  6907. +
  6908. + const std::string& parser_error() const { return parser_error_; }
  6909. + void set_parser_error(const std::string& parser_error) {
  6910. + parser_error_ = parser_error;
  6911. + }
  6912. +
  6913. + bool force_disabled() const { return force_disabled_; }
  6914. + void set_force_disabled() {
  6915. + force_disabled_ = true;
  6916. + }
  6917. +
  6918. + // The place in the document to run the script.
  6919. + RunLocation run_location() const { return run_location_; }
  6920. + void set_run_location(RunLocation location) { run_location_ = location; }
  6921. +
  6922. + // Whether to emulate greasemonkey when running this script.
  6923. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6924. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6925. +
  6926. + // Whether to match all frames, or only the top one.
  6927. + bool match_all_frames() const { return match_all_frames_; }
  6928. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6929. +
  6930. + // Whether to match the origin as a fallback if the URL cannot be used
  6931. + // directly.
  6932. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6933. + return match_origin_as_fallback_;
  6934. + }
  6935. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6936. + match_origin_as_fallback_ = val;
  6937. + }
  6938. +
  6939. + // The globs, if any, that determine which pages this script runs against.
  6940. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6941. + const std::vector<std::string>& globs() const { return globs_; }
  6942. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6943. + void clear_globs() { globs_.clear(); }
  6944. + const std::vector<std::string>& exclude_globs() const {
  6945. + return exclude_globs_;
  6946. + }
  6947. + void add_exclude_glob(const std::string& glob) {
  6948. + exclude_globs_.push_back(glob);
  6949. + }
  6950. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6951. +
  6952. + // The URLPatterns, if any, that determine which pages this script runs
  6953. + // against.
  6954. + const URLPatternSet& url_patterns() const { return url_set_; }
  6955. + void add_url_pattern(const URLPattern& pattern);
  6956. + const URLPatternSet& exclude_url_patterns() const {
  6957. + return exclude_url_set_;
  6958. + }
  6959. + void add_exclude_url_pattern(const URLPattern& pattern);
  6960. +
  6961. + // List of js scripts for this user script
  6962. + FileList& js_scripts() { return js_scripts_; }
  6963. + const FileList& js_scripts() const { return js_scripts_; }
  6964. +
  6965. + // List of css scripts for this user script
  6966. + FileList& css_scripts() { return css_scripts_; }
  6967. + const FileList& css_scripts() const { return css_scripts_; }
  6968. +
  6969. + const std::string& extension_id() const { return host_id_.id(); }
  6970. +
  6971. + const HostID& host_id() const { return host_id_; }
  6972. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  6973. +
  6974. + const ConsumerInstanceType& consumer_instance_type() const {
  6975. + return consumer_instance_type_;
  6976. + }
  6977. + void set_consumer_instance_type(
  6978. + const ConsumerInstanceType& consumer_instance_type) {
  6979. + consumer_instance_type_ = consumer_instance_type;
  6980. + }
  6981. +
  6982. + int id() const { return user_script_id_; }
  6983. + void set_id(int id) { user_script_id_ = id; }
  6984. +
  6985. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  6986. + // belong here. We should be able to determine this in the renderer/ where it
  6987. + // is used.
  6988. + bool is_incognito_enabled() const { return incognito_enabled_; }
  6989. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  6990. +
  6991. + // Returns true if the script should be applied to the specified URL, false
  6992. + // otherwise.
  6993. + bool MatchesURL(const GURL& url) const;
  6994. +
  6995. + // Returns true if the script should be applied to the given
  6996. + // |effective_document_url|. It is the caller's responsibility to calculate
  6997. + // |effective_document_url| based on match_origin_as_fallback().
  6998. + bool MatchesDocument(const GURL& effective_document_url,
  6999. + bool is_subframe) const;
  7000. +
  7001. + // Serializes the UserScript into a pickle. The content of the scripts and
  7002. + // paths to UserScript::Files will not be serialized!
  7003. + void Pickle(base::Pickle* pickle) const;
  7004. +
  7005. + // Deserializes the script from a pickle. Note that this always succeeds
  7006. + // because presumably we were the one that pickled it, and we did it
  7007. + // correctly.
  7008. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  7009. +
  7010. + private:
  7011. + // base::Pickle helper functions used to pickle the individual types of
  7012. + // components.
  7013. + void PickleGlobs(base::Pickle* pickle,
  7014. + const std::vector<std::string>& globs) const;
  7015. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  7016. + void PickleURLPatternSet(base::Pickle* pickle,
  7017. + const URLPatternSet& pattern_list) const;
  7018. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  7019. +
  7020. + // Unpickle helper functions used to unpickle individual types of components.
  7021. + void UnpickleGlobs(const base::Pickle& pickle,
  7022. + base::PickleIterator* iter,
  7023. + std::vector<std::string>* globs);
  7024. + void UnpickleHostID(const base::Pickle& pickle,
  7025. + base::PickleIterator* iter,
  7026. + HostID* host_id);
  7027. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  7028. + base::PickleIterator* iter,
  7029. + URLPatternSet* pattern_list);
  7030. + void UnpickleScripts(const base::Pickle& pickle,
  7031. + base::PickleIterator* iter,
  7032. + FileList* scripts);
  7033. +
  7034. + // The location to run the script inside the document.
  7035. + RunLocation run_location_ = DOCUMENT_IDLE;
  7036. +
  7037. + // The namespace of the script. This is used by Greasemonkey in the same way
  7038. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  7039. + std::string name_space_;
  7040. +
  7041. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  7042. + std::string name_;
  7043. +
  7044. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  7045. + std::string description_;
  7046. +
  7047. + // Parser error to show to user
  7048. + std::string parser_error_;
  7049. +
  7050. + // A version number of the script. Only used when parsing Greasemonkey-style
  7051. + // scripts.
  7052. + std::string version_;
  7053. +
  7054. + // Greasemonkey-style globs that determine pages to inject the script into.
  7055. + // These are only used with standalone scripts.
  7056. + std::vector<std::string> globs_;
  7057. + std::vector<std::string> exclude_globs_;
  7058. +
  7059. + // URLPatterns that determine pages to inject the script into. These are
  7060. + // only used with scripts that are part of extensions.
  7061. + URLPatternSet url_set_;
  7062. + URLPatternSet exclude_url_set_;
  7063. +
  7064. + // List of js scripts defined in content_scripts
  7065. + FileList js_scripts_;
  7066. +
  7067. + // List of css scripts defined in content_scripts
  7068. + FileList css_scripts_;
  7069. +
  7070. + // internal key of scripts
  7071. + std::string key_;
  7072. +
  7073. + std::string file_path_;
  7074. +
  7075. + // url source of script
  7076. + std::string url_source_;
  7077. +
  7078. + // The ID of the host this script is a part of. The |ID| of the
  7079. + // |host_id| can be empty if the script is a "standlone" user script.
  7080. + HostID host_id_;
  7081. +
  7082. + // The type of the consumer instance that the script will be injected.
  7083. + ConsumerInstanceType consumer_instance_type_ = TAB;
  7084. +
  7085. + // The globally-unique id associated with this user script. -1 indicates
  7086. + // "invalid".
  7087. + int user_script_id_ = -1;
  7088. +
  7089. + // Whether we should try to emulate Greasemonkey's APIs when running this
  7090. + // script.
  7091. + bool emulate_greasemonkey_ = false;
  7092. +
  7093. + // Whether the user script should run in all frames, or only just the top one.
  7094. + bool match_all_frames_ = false;
  7095. +
  7096. + // Whether the user script should run in frames whose initiator / precursor
  7097. + // origin matches a match pattern, if an appropriate URL cannot be found for
  7098. + // the frame for matching purposes, such as in the case of about:, data:, and
  7099. + // other schemes.
  7100. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  7101. + MatchOriginAsFallbackBehavior::kNever;
  7102. +
  7103. + // True if the script should be injected into an incognito tab.
  7104. + bool incognito_enabled_ = false;
  7105. +
  7106. + // Script cannot be enabled
  7107. + bool force_disabled_ = false;
  7108. +};
  7109. +
  7110. +// Information we need while removing scripts from a UserScriptLoader.
  7111. +struct UserScriptIDPair {
  7112. + UserScriptIDPair(int id, const HostID& host_id);
  7113. + explicit UserScriptIDPair(int id);
  7114. +
  7115. + int id;
  7116. + HostID host_id;
  7117. +};
  7118. +
  7119. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  7120. +
  7121. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  7122. +
  7123. +} // namespace extensions
  7124. +
  7125. +#endif // USERSCRIPTS_COMMON_USER_SCRIPT_H_
  7126. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  7127. new file mode 100644
  7128. --- /dev/null
  7129. +++ b/components/user_scripts/common/user_scripts_features.cc
  7130. @@ -0,0 +1,32 @@
  7131. +/*
  7132. + This file is part of Bromite.
  7133. +
  7134. + Bromite is free software: you can redistribute it and/or modify
  7135. + it under the terms of the GNU General Public License as published by
  7136. + the Free Software Foundation, either version 3 of the License, or
  7137. + (at your option) any later version.
  7138. +
  7139. + Bromite is distributed in the hope that it will be useful,
  7140. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7141. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7142. + GNU General Public License for more details.
  7143. +
  7144. + You should have received a copy of the GNU General Public License
  7145. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7146. +*/
  7147. +
  7148. +#include "user_scripts_features.h"
  7149. +
  7150. +#include "build/build_config.h"
  7151. +
  7152. +namespace user_scripts {
  7153. +
  7154. +namespace features {
  7155. +
  7156. +const base::Feature kEnableLoggingUserScripts =
  7157. + {"EnableLoggingUserScripts",
  7158. + base::FEATURE_DISABLED_BY_DEFAULT};
  7159. +
  7160. +}
  7161. +
  7162. +}
  7163. \ No newline at end of file
  7164. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  7165. new file mode 100644
  7166. --- /dev/null
  7167. +++ b/components/user_scripts/common/user_scripts_features.h
  7168. @@ -0,0 +1,34 @@
  7169. +/*
  7170. + This file is part of Bromite.
  7171. +
  7172. + Bromite is free software: you can redistribute it and/or modify
  7173. + it under the terms of the GNU General Public License as published by
  7174. + the Free Software Foundation, either version 3 of the License, or
  7175. + (at your option) any later version.
  7176. +
  7177. + Bromite is distributed in the hope that it will be useful,
  7178. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7179. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7180. + GNU General Public License for more details.
  7181. +
  7182. + You should have received a copy of the GNU General Public License
  7183. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7184. +*/
  7185. +
  7186. +#ifndef USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7187. +#define USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7188. +
  7189. +// This file defines all the base::FeatureList features for the Password Manager
  7190. +// module.
  7191. +
  7192. +#include "base/feature_list.h"
  7193. +
  7194. +namespace user_scripts {
  7195. +
  7196. +namespace features {
  7197. + extern const base::Feature kEnableLoggingUserScripts;
  7198. +}
  7199. +
  7200. +}
  7201. +
  7202. +#endif
  7203. \ No newline at end of file
  7204. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  7205. new file mode 100755
  7206. --- /dev/null
  7207. +++ b/components/user_scripts/common/view_type.cc
  7208. @@ -0,0 +1,39 @@
  7209. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7210. +// Use of this source code is governed by a BSD-style license that can be
  7211. +// found in the LICENSE file.
  7212. +
  7213. +#include "view_type.h"
  7214. +
  7215. +#include "base/strings/string_piece.h"
  7216. +
  7217. +namespace user_scripts {
  7218. +
  7219. +bool GetViewTypeFromString(const std::string& view_type,
  7220. + ViewType* view_type_out) {
  7221. + // TODO(devlin): This map doesn't contain the following values:
  7222. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  7223. + // - VIEW_TYPE_COMPONENT
  7224. + // - VIEW_TYPE_EXTENSION_GUEST
  7225. + // Why? Is it just because we don't expose those types to JS?
  7226. + static const struct {
  7227. + ViewType type;
  7228. + base::StringPiece name;
  7229. + } constexpr kTypeMap[] = {
  7230. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  7231. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  7232. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  7233. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  7234. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  7235. + };
  7236. +
  7237. + for (const auto& entry : kTypeMap) {
  7238. + if (entry.name == view_type) {
  7239. + *view_type_out = entry.type;
  7240. + return true;
  7241. + }
  7242. + }
  7243. +
  7244. + return false;
  7245. +}
  7246. +
  7247. +} // namespace extensions
  7248. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  7249. new file mode 100755
  7250. --- /dev/null
  7251. +++ b/components/user_scripts/common/view_type.h
  7252. @@ -0,0 +1,48 @@
  7253. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7254. +// Use of this source code is governed by a BSD-style license that can be
  7255. +// found in the LICENSE file.
  7256. +
  7257. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7258. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7259. +
  7260. +#include <string>
  7261. +
  7262. +namespace user_scripts {
  7263. +
  7264. +// Icky RTTI used by a few systems to distinguish the host type of a given
  7265. +// WebContents.
  7266. +//
  7267. +// Do not change or reuse the the entry values in this list as this is used in
  7268. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  7269. +//
  7270. +// TODO(aa): Remove this and teach those systems to keep track of their own
  7271. +// data.
  7272. +enum ViewType {
  7273. + VIEW_TYPE_INVALID = 0,
  7274. + // VIEW_TYPE_APP_WINDOW = 1,
  7275. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  7276. +
  7277. + // // For custom parts of Chrome if no other type applies.
  7278. + // VIEW_TYPE_COMPONENT = 3,
  7279. +
  7280. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  7281. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  7282. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  7283. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  7284. +
  7285. + // Panels were removed in https://crbug.com/571511.
  7286. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  7287. +
  7288. + VIEW_TYPE_TAB_CONTENTS = 9,
  7289. +
  7290. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  7291. +};
  7292. +
  7293. +// Matches the |view_type| to the corresponding ViewType, and populates
  7294. +// |view_type_out|. Returns true if a match is found.
  7295. +bool GetViewTypeFromString(const std::string& view_type,
  7296. + ViewType* view_type_out);
  7297. +
  7298. +} // namespace extensions
  7299. +
  7300. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7301. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  7302. new file mode 100755
  7303. --- /dev/null
  7304. +++ b/components/user_scripts/renderer/BUILD.gn
  7305. @@ -0,0 +1,67 @@
  7306. +# Copyright 2015 The Chromium Authors. All rights reserved.
  7307. +# Use of this source code is governed by a BSD-style license that can be
  7308. +# found in the LICENSE file.
  7309. +
  7310. +import("//tools/grit/grit_rule.gni")
  7311. +import("//tools/grit/repack.gni")
  7312. +
  7313. +group("user_scripts_resources") {
  7314. + public_deps = [
  7315. + ":user_scripts_renderer_resources",
  7316. + ]
  7317. +}
  7318. +
  7319. +grit("user_scripts_renderer_resources") {
  7320. + source = "resources/user_scripts_renderer_resources.grd"
  7321. + outputs = [
  7322. + "grit/user_scripts_renderer_resources.h",
  7323. + "user_scripts_renderer_resources.pak",
  7324. + ]
  7325. + grit_flags = [
  7326. + "-E",
  7327. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  7328. + ]
  7329. +}
  7330. +
  7331. +static_library("renderer") {
  7332. + sources = [
  7333. + "extension_frame_helper.cc",
  7334. + "extension_frame_helper.h",
  7335. + "injection_host.cc",
  7336. + "injection_host.h",
  7337. + "script_injection_manager.cc",
  7338. + "script_injection_manager.h",
  7339. + "script_injection_callback.cc",
  7340. + "script_injection_callback.h",
  7341. + "script_injection.cc",
  7342. + "script_injection.h",
  7343. + "script_injector.h",
  7344. + "script_context.cc",
  7345. + "script_context.h",
  7346. + "scripts_run_info.cc",
  7347. + "scripts_run_info.h",
  7348. + "user_script_injector.cc",
  7349. + "user_script_injector.h",
  7350. + "user_script_set_manager.cc",
  7351. + "user_script_set_manager.h",
  7352. + "user_script_set.cc",
  7353. + "user_script_set.h",
  7354. + "user_scripts_dispatcher.cc",
  7355. + "user_scripts_dispatcher.h",
  7356. + "user_scripts_renderer_client.cc",
  7357. + "user_scripts_renderer_client.h",
  7358. + "web_ui_injection_host.cc",
  7359. + "web_ui_injection_host.h",
  7360. + ]
  7361. +
  7362. + deps = [
  7363. + ":user_scripts_resources",
  7364. + "//base",
  7365. + "//content/public/common",
  7366. + "//content/public/renderer",
  7367. + "//components/user_scripts/common",
  7368. + "//mojo/public/cpp/bindings",
  7369. + "//third_party/blink/public:blink_headers",
  7370. + "//v8",
  7371. + ]
  7372. +}
  7373. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  7374. new file mode 100755
  7375. --- /dev/null
  7376. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  7377. @@ -0,0 +1,96 @@
  7378. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7379. +// Use of this source code is governed by a BSD-style license that can be
  7380. +// found in the LICENSE file.
  7381. +
  7382. +#include "extension_frame_helper.h"
  7383. +
  7384. +#include <set>
  7385. +
  7386. +#include "base/metrics/histogram_macros.h"
  7387. +#include "base/strings/string_util.h"
  7388. +#include "base/timer/elapsed_timer.h"
  7389. +#include "content/public/renderer/render_frame.h"
  7390. +#include "content/public/renderer/render_view.h"
  7391. +#include "../common/constants.h"
  7392. +#include "third_party/blink/public/platform/web_security_origin.h"
  7393. +#include "third_party/blink/public/web/web_console_message.h"
  7394. +#include "third_party/blink/public/web/web_document.h"
  7395. +#include "third_party/blink/public/web/web_document_loader.h"
  7396. +#include "third_party/blink/public/web/web_local_frame.h"
  7397. +#include "third_party/blink/public/web/web_settings.h"
  7398. +#include "third_party/blink/public/web/web_view.h"
  7399. +
  7400. +namespace user_scripts {
  7401. +
  7402. +namespace {
  7403. +
  7404. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  7405. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  7406. +
  7407. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  7408. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  7409. +void RunCallbacksWhileFrameIsValid(
  7410. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  7411. + std::vector<base::OnceClosure>* callbacks_to_be_run_and_cleared) {
  7412. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  7413. + // callbacks that are added during the iteration.
  7414. + std::vector<base::OnceClosure> callbacks;
  7415. + callbacks_to_be_run_and_cleared->swap(callbacks);
  7416. + for (auto& callback : callbacks) {
  7417. + std::move(callback).Run();
  7418. + if (!frame_helper.get())
  7419. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  7420. + }
  7421. +}
  7422. +
  7423. +} // namespace
  7424. +
  7425. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  7426. + : content::RenderFrameObserver(render_frame),
  7427. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  7428. + tab_id_(-1) {
  7429. + g_frame_helpers.Get().insert(this);
  7430. +}
  7431. +
  7432. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  7433. + g_frame_helpers.Get().erase(this);
  7434. +}
  7435. +
  7436. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  7437. + base::OnceClosure callback) {
  7438. + document_element_created_callbacks_.push_back(std::move(callback));
  7439. +}
  7440. +
  7441. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  7442. + base::OnceClosure callback) {
  7443. + document_load_finished_callbacks_.push_back(std::move(callback));
  7444. +}
  7445. +
  7446. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  7447. + base::OnceClosure callback) {
  7448. + document_idle_callbacks_.push_back(std::move(callback));
  7449. +}
  7450. +
  7451. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  7452. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7453. + &document_element_created_callbacks_);
  7454. + // |this| might be dead by now.
  7455. +}
  7456. +
  7457. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  7458. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7459. + &document_load_finished_callbacks_);
  7460. + // |this| might be dead by now.
  7461. +}
  7462. +
  7463. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  7464. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7465. + &document_idle_callbacks_);
  7466. + // |this| might be dead by now.
  7467. +}
  7468. +
  7469. +void ExtensionFrameHelper::OnDestruct() {
  7470. + delete this;
  7471. +}
  7472. +
  7473. +} // namespace user_scripts
  7474. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  7475. new file mode 100755
  7476. --- /dev/null
  7477. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  7478. @@ -0,0 +1,91 @@
  7479. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7480. +// Use of this source code is governed by a BSD-style license that can be
  7481. +// found in the LICENSE file.
  7482. +
  7483. +#ifndef USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7484. +#define USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7485. +
  7486. +#include <string>
  7487. +#include <vector>
  7488. +
  7489. +#include "base/callback_forward.h"
  7490. +#include "base/memory/weak_ptr.h"
  7491. +#include "content/public/renderer/render_frame_observer.h"
  7492. +#include "content/public/renderer/render_frame_observer_tracker.h"
  7493. +#include "../common/view_type.h"
  7494. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  7495. +#include "v8/include/v8.h"
  7496. +
  7497. +struct ExtensionMsg_ExternalConnectionInfo;
  7498. +struct ExtensionMsg_TabConnectionInfo;
  7499. +
  7500. +namespace base {
  7501. +class ListValue;
  7502. +}
  7503. +
  7504. +namespace user_scripts {
  7505. +
  7506. +class Dispatcher;
  7507. +struct Message;
  7508. +struct PortId;
  7509. +class ScriptContext;
  7510. +
  7511. +// RenderFrame-level plumbing for extension features.
  7512. +class ExtensionFrameHelper
  7513. + : public content::RenderFrameObserver,
  7514. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  7515. + public:
  7516. + ExtensionFrameHelper(const ExtensionFrameHelper&) = delete;
  7517. + ExtensionFrameHelper& operator=(const ExtensionFrameHelper&) = delete;
  7518. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  7519. + Dispatcher* extension_dispatcher*/);
  7520. + ~ExtensionFrameHelper() override;
  7521. +
  7522. + int tab_id() const { return tab_id_; }
  7523. +
  7524. + // Called when the document element has been inserted in this frame. This
  7525. + // method may invoke untrusted JavaScript code that invalidate the frame and
  7526. + // this ExtensionFrameHelper.
  7527. + void RunScriptsAtDocumentStart();
  7528. +
  7529. + // Called after the DOMContentLoaded event has fired.
  7530. + void RunScriptsAtDocumentEnd();
  7531. +
  7532. + // Called before the window.onload event is fired.
  7533. + void RunScriptsAtDocumentIdle();
  7534. +
  7535. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  7536. + // notification. Only call this when you are certain that there will be such a
  7537. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  7538. + // Otherwise the callback is never invoked, or invoked for a document that you
  7539. + // were not expecting.
  7540. + void ScheduleAtDocumentStart(base::OnceClosure callback);
  7541. +
  7542. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  7543. + void ScheduleAtDocumentEnd(base::OnceClosure callback);
  7544. +
  7545. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  7546. + void ScheduleAtDocumentIdle(base::OnceClosure callback);
  7547. +
  7548. + private:
  7549. +
  7550. + void OnDestruct() override;
  7551. +
  7552. + // The id of the tab the render frame is attached to.
  7553. + int tab_id_;
  7554. +
  7555. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  7556. + std::vector<base::OnceClosure> document_element_created_callbacks_;
  7557. +
  7558. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  7559. + std::vector<base::OnceClosure> document_load_finished_callbacks_;
  7560. +
  7561. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  7562. + std::vector<base::OnceClosure> document_idle_callbacks_;
  7563. +
  7564. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  7565. +};
  7566. +
  7567. +} // namespace extensions
  7568. +
  7569. +#endif // USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7570. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  7571. new file mode 100755
  7572. --- /dev/null
  7573. +++ b/components/user_scripts/renderer/injection_host.cc
  7574. @@ -0,0 +1,12 @@
  7575. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7576. +// Use of this source code is governed by a BSD-style license that can be
  7577. +// found in the LICENSE file.
  7578. +
  7579. +#include "injection_host.h"
  7580. +
  7581. +InjectionHost::InjectionHost(const HostID& host_id) :
  7582. + id_(host_id) {
  7583. +}
  7584. +
  7585. +InjectionHost::~InjectionHost() {
  7586. +}
  7587. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  7588. new file mode 100755
  7589. --- /dev/null
  7590. +++ b/components/user_scripts/renderer/injection_host.h
  7591. @@ -0,0 +1,41 @@
  7592. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7593. +// Use of this source code is governed by a BSD-style license that can be
  7594. +// found in the LICENSE file.
  7595. +
  7596. +#ifndef USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7597. +#define USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7598. +
  7599. +#include "../common/host_id.h"
  7600. +#include "url/gurl.h"
  7601. +
  7602. +namespace content {
  7603. +class RenderFrame;
  7604. +}
  7605. +
  7606. +// An interface for all kinds of hosts who own user scripts.
  7607. +class InjectionHost {
  7608. + public:
  7609. + InjectionHost(const InjectionHost&) = delete;
  7610. + InjectionHost& operator=(const InjectionHost&) = delete;
  7611. + InjectionHost(const HostID& host_id);
  7612. + virtual ~InjectionHost();
  7613. +
  7614. + // Returns the CSP to be used for the isolated world. Currently this only
  7615. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  7616. + // bypassed.
  7617. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  7618. +
  7619. + // The base url for the host.
  7620. + virtual const GURL& url() const = 0;
  7621. +
  7622. + // The human-readable name of the host.
  7623. + virtual const std::string& name() const = 0;
  7624. +
  7625. + const HostID& id() const { return id_; }
  7626. +
  7627. + private:
  7628. + // The ID of the host.
  7629. + HostID id_;
  7630. +};
  7631. +
  7632. +#endif // USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7633. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7634. new file mode 100755
  7635. --- /dev/null
  7636. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7637. @@ -0,0 +1,82 @@
  7638. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7639. +// Use of this source code is governed by a BSD-style license that can be
  7640. +// found in the LICENSE file.
  7641. +
  7642. +// -----------------------------------------------------------------------------
  7643. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  7644. +// have your change take effect.
  7645. +// -----------------------------------------------------------------------------
  7646. +
  7647. +// Partial implementation of the Greasemonkey API, see:
  7648. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  7649. +
  7650. +function GM_addStyle(css) {
  7651. + var parent = document.getElementsByTagName("head")[0];
  7652. + if (!parent) {
  7653. + parent = document.documentElement;
  7654. + }
  7655. + var style = document.createElement("style");
  7656. + style.type = "text/css";
  7657. + var textNode = document.createTextNode(css);
  7658. + style.appendChild(textNode);
  7659. + parent.appendChild(style);
  7660. +}
  7661. +
  7662. +function GM_xmlhttpRequest(details) {
  7663. + function setupEvent(xhr, url, eventName, callback) {
  7664. + xhr[eventName] = function () {
  7665. + var isComplete = xhr.readyState == 4;
  7666. + var responseState = {
  7667. + responseText: xhr.responseText,
  7668. + readyState: xhr.readyState,
  7669. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  7670. + status: isComplete ? xhr.status : 0,
  7671. + statusText: isComplete ? xhr.statusText : "",
  7672. + finalUrl: isComplete ? url : ""
  7673. + };
  7674. + callback(responseState);
  7675. + };
  7676. + }
  7677. +
  7678. + var xhr = new XMLHttpRequest();
  7679. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  7680. + for (var i = 0; i < eventNames.length; i++ ) {
  7681. + var eventName = eventNames[i];
  7682. + if (eventName in details) {
  7683. + setupEvent(xhr, details.url, eventName, details[eventName]);
  7684. + }
  7685. + }
  7686. +
  7687. + xhr.open(details.method, details.url);
  7688. +
  7689. + if (details.overrideMimeType) {
  7690. + xhr.overrideMimeType(details.overrideMimeType);
  7691. + }
  7692. + if (details.headers) {
  7693. + for (var header in details.headers) {
  7694. + xhr.setRequestHeader(header, details.headers[header]);
  7695. + }
  7696. + }
  7697. + xhr.send(details.data ? details.data : null);
  7698. +}
  7699. +
  7700. +function GM_openInTab(url) {
  7701. + window.open(url, "");
  7702. +}
  7703. +
  7704. +function GM_log(message) {
  7705. + window.console.log(message);
  7706. +}
  7707. +
  7708. +(function() {
  7709. + function generateGreasemonkeyStub(name) {
  7710. + return function() {
  7711. + console.log("%s is not supported.", name);
  7712. + };
  7713. + }
  7714. +
  7715. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  7716. + for (var i = 0, api; api = apis[i]; i++) {
  7717. + window[api] = generateGreasemonkeyStub(api);
  7718. + }
  7719. +})();
  7720. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7721. new file mode 100755
  7722. --- /dev/null
  7723. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7724. @@ -0,0 +1,14 @@
  7725. +<?xml version="1.0" encoding="UTF-8"?>
  7726. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  7727. + <outputs>
  7728. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  7729. + <emit emit_type='prepend'></emit>
  7730. + </output>
  7731. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  7732. + </outputs>
  7733. + <release seq="1">
  7734. + <includes>
  7735. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  7736. + </includes>
  7737. + </release>
  7738. +</grit>
  7739. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  7740. new file mode 100755
  7741. --- /dev/null
  7742. +++ b/components/user_scripts/renderer/script_context.cc
  7743. @@ -0,0 +1,215 @@
  7744. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7745. +// Use of this source code is governed by a BSD-style license that can be
  7746. +// found in the LICENSE file.
  7747. +
  7748. +#include "script_context.h"
  7749. +
  7750. +#include "base/command_line.h"
  7751. +#include "base/containers/flat_set.h"
  7752. +#include "base/containers/contains.h"
  7753. +#include "base/logging.h"
  7754. +#include "base/no_destructor.h"
  7755. +#include "base/stl_util.h"
  7756. +#include "base/strings/string_util.h"
  7757. +#include "base/strings/stringprintf.h"
  7758. +#include "base/values.h"
  7759. +#include "content/public/common/content_switches.h"
  7760. +#include "content/public/common/url_constants.h"
  7761. +#include "content/public/renderer/render_frame.h"
  7762. +#include "../common/constants.h"
  7763. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  7764. +#include "third_party/blink/public/platform/web_security_origin.h"
  7765. +#include "third_party/blink/public/web/web_document.h"
  7766. +#include "third_party/blink/public/web/web_document_loader.h"
  7767. +#include "third_party/blink/public/web/web_local_frame.h"
  7768. +#include "third_party/blink/public/web/web_navigation_params.h"
  7769. +#include "v8/include/v8.h"
  7770. +
  7771. +namespace user_scripts {
  7772. +
  7773. +namespace {
  7774. +
  7775. +GURL GetEffectiveDocumentURL(
  7776. + blink::WebLocalFrame* frame,
  7777. + const GURL& document_url,
  7778. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  7779. + bool allow_inaccessible_parents) {
  7780. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  7781. + switch (match_origin_as_fallback) {
  7782. + case MatchOriginAsFallbackBehavior::kNever:
  7783. + return false;
  7784. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  7785. + return document_url.SchemeIs(url::kAboutScheme);
  7786. + case MatchOriginAsFallbackBehavior::kAlways:
  7787. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  7788. + return document_url.SchemeIs(url::kAboutScheme) ||
  7789. + document_url.SchemeIs(url::kDataScheme);
  7790. + }
  7791. +
  7792. + NOTREACHED();
  7793. + };
  7794. +
  7795. + // If we don't need to consider the origin, we're done.
  7796. + if (!should_consider_origin())
  7797. + return document_url;
  7798. +
  7799. + // Get the "security origin" for the frame. For about: frames, this is the
  7800. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7801. + // https://example.com will have the security origin of https://example.com.
  7802. + // Other frames, like data: frames, will have an opaque origin. For these,
  7803. + // we can get the precursor origin.
  7804. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7805. + const url::Origin frame_origin = web_frame_origin;
  7806. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7807. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7808. +
  7809. + // When there's no valid tuple (which can happen in the case of e.g. a
  7810. + // browser-initiated navigation to an opaque URL), there's no origin to
  7811. + // fallback to. Bail.
  7812. + if (!tuple_or_precursor_tuple.IsValid())
  7813. + return document_url;
  7814. +
  7815. + const url::Origin origin_or_precursor_origin =
  7816. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7817. +
  7818. + if (!allow_inaccessible_parents &&
  7819. + !web_frame_origin.CanAccess(
  7820. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7821. + // The frame can't access its precursor. Bail.
  7822. + return document_url;
  7823. + }
  7824. +
  7825. + // Looks like the initiator origin is an appropriate fallback!
  7826. +
  7827. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7828. + // The easy case! We use the origin directly. We're done.
  7829. + return origin_or_precursor_origin.GetURL();
  7830. + }
  7831. +
  7832. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7833. + match_origin_as_fallback);
  7834. +
  7835. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7836. + // match patterns that are associated with paths as well, not just origins.
  7837. + // For instance, if an extension wants to run on google.com/maps/* with
  7838. + // match_about_blank true, then it should run on about:-scheme frames created
  7839. + // by google.com/maps, but not about:-scheme frames created by google.com
  7840. + // (which is what the precursor tuple origin would be).
  7841. +
  7842. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7843. + // with the same origin as the precursor and return its URL.
  7844. + // Note: This can return the incorrect result, e.g. if a parent frame
  7845. + // navigates a grandchild frame.
  7846. + blink::WebFrame* parent = frame;
  7847. + GURL parent_url;
  7848. + blink::WebDocument parent_document;
  7849. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7850. + do {
  7851. + already_visited_frames.insert(parent);
  7852. + if (parent->Parent())
  7853. + parent = parent->Parent();
  7854. + else
  7855. + parent = parent->Opener();
  7856. +
  7857. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7858. + // https://crbug.com/883526.
  7859. + if (base::Contains(already_visited_frames, parent))
  7860. + return document_url;
  7861. +
  7862. + parent_document = parent && parent->IsWebLocalFrame()
  7863. + ? parent->ToWebLocalFrame()->GetDocument()
  7864. + : blink::WebDocument();
  7865. +
  7866. + // We reached the end of the ancestral chain without finding a valid parent,
  7867. + // or found a remote web frame (in which case, it's a different origin).
  7868. + // Bail and use the original URL.
  7869. + if (parent_document.IsNull())
  7870. + return document_url;
  7871. +
  7872. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7873. + url::Origin(parent->GetSecurityOrigin())
  7874. + .GetTupleOrPrecursorTupleIfOpaque();
  7875. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7876. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7877. + // The parent has a different tuple origin than frame; this could happen
  7878. + // in edge cases where a parent navigates an iframe or popup of a child
  7879. + // frame at a different origin. [1] In this case, bail, since we can't
  7880. + // find a full URL (i.e., one including the path) with the same security
  7881. + // origin to use for the frame in question.
  7882. + // [1] Consider a frame tree like:
  7883. + // <html> <!--example.com-->
  7884. + // <iframe id="a" src="a.com">
  7885. + // <iframe id="b" src="b.com"></iframe>
  7886. + // </iframe>
  7887. + // </html>
  7888. + // Frame "a" is cross-origin from the top-level frame, and so the
  7889. + // example.com top-level frame can't directly access frame "b". However,
  7890. + // it can navigate it through
  7891. + // window.frames[0].frames[0].location.href = 'about:blank';
  7892. + // In that case, the precursor origin tuple origin of frame "b" would be
  7893. + // example.com, but the parent tuple origin is a.com.
  7894. + // Note that usually, this would have bailed earlier with a remote frame,
  7895. + // but it may not if we're at the process limit.
  7896. + return document_url;
  7897. + }
  7898. +
  7899. + parent_url = GURL(parent_document.Url());
  7900. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7901. +
  7902. + DCHECK(!parent_url.is_empty());
  7903. + DCHECK(!parent_document.IsNull());
  7904. +
  7905. + // We should know that the frame can access the parent document (unless we
  7906. + // explicitly allow it not to), since it has the same tuple origin as the
  7907. + // frame, and we checked the frame access above.
  7908. + DCHECK(allow_inaccessible_parents ||
  7909. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7910. + return parent_url;
  7911. +}
  7912. +
  7913. +using FrameToDocumentLoader =
  7914. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7915. +
  7916. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7917. + static base::NoDestructor<FrameToDocumentLoader> map;
  7918. + return *map;
  7919. +}
  7920. +
  7921. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7922. + const blink::WebLocalFrame* frame) {
  7923. + auto& map = FrameDocumentLoaderMap();
  7924. + auto it = map.find(frame);
  7925. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7926. +}
  7927. +
  7928. +} // namespace
  7929. +
  7930. +// static
  7931. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7932. + const blink::WebLocalFrame* frame) {
  7933. + // Normally we would use frame->document().url() to determine the document's
  7934. + // URL, but to decide whether to inject a content script, we use the URL from
  7935. + // the data source. This "quirk" helps prevents content scripts from
  7936. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7937. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7938. + // changes to match the parent document after Gmail document.writes into
  7939. + // it to create the editor.
  7940. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7941. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7942. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7943. +}
  7944. +
  7945. +// static
  7946. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7947. + blink::WebLocalFrame* frame,
  7948. + const GURL& document_url,
  7949. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7950. + // We explicitly allow inaccessible parents here. Extensions should still be
  7951. + // able to inject into a sandboxed iframe if it has access to the embedding
  7952. + // origin.
  7953. + constexpr bool allow_inaccessible_parents = true;
  7954. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7955. + allow_inaccessible_parents);
  7956. +}
  7957. +
  7958. +} // namespace extensions
  7959. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7960. new file mode 100755
  7961. --- /dev/null
  7962. +++ b/components/user_scripts/renderer/script_context.h
  7963. @@ -0,0 +1,69 @@
  7964. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7965. +// Use of this source code is governed by a BSD-style license that can be
  7966. +// found in the LICENSE file.
  7967. +
  7968. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7969. +#define USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7970. +
  7971. +#include <memory>
  7972. +#include <string>
  7973. +#include <utility>
  7974. +#include <vector>
  7975. +
  7976. +#include "base/callback.h"
  7977. +#include "base/compiler_specific.h"
  7978. +#include "base/threading/thread_checker.h"
  7979. +#include "base/unguessable_token.h"
  7980. +#include "../common/script_constants.h"
  7981. +#include "script_injection_callback.h"
  7982. +#include "url/gurl.h"
  7983. +#include "v8/include/v8.h"
  7984. +
  7985. +namespace blink {
  7986. +class WebDocumentLoader;
  7987. +class WebLocalFrame;
  7988. +}
  7989. +
  7990. +namespace content {
  7991. +class RenderFrame;
  7992. +}
  7993. +
  7994. +namespace user_scripts {
  7995. +
  7996. +// Extensions wrapper for a v8::Context.
  7997. +//
  7998. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  7999. +// destroyed that thread.
  8000. +//
  8001. +// Note that ScriptContexts bound to worker threads will not have the full
  8002. +// functionality as those bound to the main RenderThread.
  8003. +class ScriptContext {
  8004. + public:
  8005. + ScriptContext(const ScriptContext&) = delete;
  8006. + ScriptContext& operator=(const ScriptContext&) = delete;
  8007. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  8008. + // vaguely ScriptContext related, there's enough here that they probably
  8009. + // warrant another class or utility file.
  8010. +
  8011. + // Utility to get the URL we will match against for a frame. If the frame has
  8012. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  8013. + // The returned URL may be invalid.
  8014. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  8015. +
  8016. + // Used to determine the "effective" URL for extension script injection.
  8017. + // If |document_url| is an about: or data: URL, returns the URL of the first
  8018. + // frame without an about: or data: URL that matches the initiator origin.
  8019. + // This may not be the immediate parent. Returns |document_url| if it is not
  8020. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  8021. + // or if a suitable parent cannot be found.
  8022. + // Considers parent contexts that cannot be accessed (as is the case for
  8023. + // sandboxed frames).
  8024. + static GURL GetEffectiveDocumentURLForInjection(
  8025. + blink::WebLocalFrame* frame,
  8026. + const GURL& document_url,
  8027. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  8028. +};
  8029. +
  8030. +} // namespace extensions
  8031. +
  8032. +#endif // USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  8033. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  8034. new file mode 100755
  8035. --- /dev/null
  8036. +++ b/components/user_scripts/renderer/script_injection.cc
  8037. @@ -0,0 +1,343 @@
  8038. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8039. +// Use of this source code is governed by a BSD-style license that can be
  8040. +// found in the LICENSE file.
  8041. +
  8042. +#include "script_injection.h"
  8043. +
  8044. +#include <map>
  8045. +#include <utility>
  8046. +
  8047. +#include "base/bind.h"
  8048. +#include "base/feature_list.h"
  8049. +#include "base/lazy_instance.h"
  8050. +#include "base/metrics/histogram_macros.h"
  8051. +#include "base/timer/elapsed_timer.h"
  8052. +#include "base/values.h"
  8053. +#include "base/logging.h"
  8054. +#include "content/public/renderer/render_frame.h"
  8055. +#include "content/public/renderer/render_frame_observer.h"
  8056. +#include "content/public/renderer/v8_value_converter.h"
  8057. +#include "../common/host_id.h"
  8058. +#include "script_injection_callback.h"
  8059. +#include "scripts_run_info.h"
  8060. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  8061. +#include "third_party/blink/public/platform/web_security_origin.h"
  8062. +#include "third_party/blink/public/platform/web_string.h"
  8063. +#include "third_party/blink/public/web/web_document.h"
  8064. +#include "third_party/blink/public/web/web_local_frame.h"
  8065. +#include "third_party/blink/public/web/web_script_source.h"
  8066. +#include "url/gurl.h"
  8067. +
  8068. +namespace user_scripts {
  8069. +
  8070. +namespace {
  8071. +
  8072. +using IsolatedWorldMap = std::map<std::string, int>;
  8073. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  8074. + LAZY_INSTANCE_INITIALIZER;
  8075. +
  8076. +const int64_t kInvalidRequestId = -1;
  8077. +
  8078. +// Gets the isolated world ID to use for the given |injection_host|. If no
  8079. +// isolated world has been created for that |injection_host| one will be created
  8080. +// and initialized.
  8081. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  8082. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  8083. +
  8084. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8085. +
  8086. + int id = 0;
  8087. + const std::string& key = injection_host->id().id();
  8088. + auto iter = isolated_worlds.find(key);
  8089. + if (iter != isolated_worlds.end()) {
  8090. + id = iter->second;
  8091. + } else {
  8092. + id = g_next_isolated_world_id++;
  8093. + // This map will tend to pile up over time, but realistically, you're never
  8094. + // going to have enough injection hosts for it to matter.
  8095. + isolated_worlds[key] = id;
  8096. + }
  8097. +
  8098. + blink::WebIsolatedWorldInfo info;
  8099. + info.security_origin =
  8100. + blink::WebSecurityOrigin::Create(injection_host->url());
  8101. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  8102. + info.stable_id = blink::WebString::FromUTF8(key);
  8103. +
  8104. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  8105. + if (csp)
  8106. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  8107. +
  8108. + // Even though there may be an existing world for this |injection_host|'s key,
  8109. + // the properties may have changed (e.g. due to an extension update).
  8110. + // Overwrite any existing entries.
  8111. + blink::SetIsolatedWorldInfo(id, info);
  8112. +
  8113. + return id;
  8114. +}
  8115. +
  8116. +// This class manages its own lifetime.
  8117. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  8118. + public:
  8119. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  8120. + : ScriptInjectionCallback(
  8121. + base::BindOnce(&TimedScriptInjectionCallback::OnCompleted,
  8122. + base::Unretained(this))),
  8123. + injection_(injection) {}
  8124. + ~TimedScriptInjectionCallback() override {}
  8125. +
  8126. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  8127. + if (injection_) {
  8128. + base::TimeTicks timestamp(base::TimeTicks::Now());
  8129. + absl::optional<base::TimeDelta> elapsed;
  8130. + // If the script will never execute (such as if the context is destroyed),
  8131. + // willExecute() will not be called, but OnCompleted() will. Only log a
  8132. + // time for execution if the script, in fact, executed.
  8133. + if (!start_time_.is_null())
  8134. + elapsed = timestamp - start_time_;
  8135. + injection_->OnJsInjectionCompleted(result, elapsed);
  8136. + }
  8137. + }
  8138. +
  8139. + void WillExecute() override {
  8140. + start_time_ = base::TimeTicks::Now();
  8141. + }
  8142. +
  8143. + private:
  8144. + base::WeakPtr<ScriptInjection> injection_;
  8145. + base::TimeTicks start_time_;
  8146. +};
  8147. +
  8148. +} // namespace
  8149. +
  8150. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  8151. +// false.
  8152. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  8153. + public:
  8154. + FrameWatcher(const FrameWatcher&) = delete;
  8155. + FrameWatcher& operator=(const FrameWatcher&) = delete;
  8156. + FrameWatcher(content::RenderFrame* render_frame,
  8157. + ScriptInjection* injection)
  8158. + : content::RenderFrameObserver(render_frame),
  8159. + injection_(injection) {}
  8160. + ~FrameWatcher() override {}
  8161. +
  8162. + private:
  8163. + void WillDetach() override { injection_->invalidate_render_frame(); }
  8164. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  8165. +
  8166. + ScriptInjection* injection_;
  8167. +};
  8168. +
  8169. +// static
  8170. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  8171. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8172. +
  8173. + for (const auto& iter : isolated_worlds) {
  8174. + if (iter.second == isolated_world_id)
  8175. + return iter.first;
  8176. + }
  8177. + return std::string();
  8178. +}
  8179. +
  8180. +// static
  8181. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  8182. + g_isolated_worlds.Get().erase(host_id);
  8183. +}
  8184. +
  8185. +ScriptInjection::ScriptInjection(
  8186. + std::unique_ptr<ScriptInjector> injector,
  8187. + content::RenderFrame* render_frame,
  8188. + std::unique_ptr<const InjectionHost> injection_host,
  8189. + UserScript::RunLocation run_location,
  8190. + bool log_activity)
  8191. + : injector_(std::move(injector)),
  8192. + render_frame_(render_frame),
  8193. + injection_host_(std::move(injection_host)),
  8194. + run_location_(run_location),
  8195. + request_id_(kInvalidRequestId),
  8196. + complete_(false),
  8197. + did_inject_js_(false),
  8198. + log_activity_(log_activity),
  8199. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  8200. + CHECK(injection_host_.get());
  8201. +}
  8202. +
  8203. +ScriptInjection::~ScriptInjection() {
  8204. + if (!complete_)
  8205. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  8206. +}
  8207. +
  8208. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  8209. + UserScript::RunLocation current_location,
  8210. + ScriptsRunInfo* scripts_run_info,
  8211. + CompletionCallback async_completion_callback) {
  8212. + if (current_location < run_location_)
  8213. + return INJECTION_WAITING; // Wait for the right location.
  8214. +
  8215. + if (request_id_ != kInvalidRequestId) {
  8216. + // We're waiting for permission right now, try again later.
  8217. + return INJECTION_WAITING;
  8218. + }
  8219. +
  8220. + if (!injection_host_) {
  8221. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8222. + return INJECTION_FINISHED; // We're done.
  8223. + }
  8224. +
  8225. + InjectionResult result = Inject(scripts_run_info);
  8226. + // If the injection is blocked, we need to set the manager so we can
  8227. + // notify it upon completion.
  8228. + if (result == INJECTION_BLOCKED)
  8229. + async_completion_callback_ = std::move(async_completion_callback);
  8230. + return result;
  8231. +}
  8232. +
  8233. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  8234. + ScriptsRunInfo* scripts_run_info) {
  8235. + if (!injection_host_) {
  8236. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8237. + return INJECTION_FINISHED;
  8238. + }
  8239. +
  8240. + return Inject(scripts_run_info);
  8241. +}
  8242. +
  8243. +void ScriptInjection::OnHostRemoved() {
  8244. + injection_host_.reset(nullptr);
  8245. +}
  8246. +
  8247. +void ScriptInjection::NotifyWillNotInject(
  8248. + ScriptInjector::InjectFailureReason reason) {
  8249. + complete_ = true;
  8250. + injector_->OnWillNotInject(reason, render_frame_);
  8251. +}
  8252. +
  8253. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  8254. + ScriptsRunInfo* scripts_run_info) {
  8255. + DCHECK(injection_host_);
  8256. + //DCHECK(scripts_run_info);
  8257. + DCHECK(!complete_);
  8258. + bool should_inject_js = injector_->ShouldInjectJs(
  8259. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  8260. + bool should_inject_css = injector_->ShouldInjectCss(
  8261. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  8262. +
  8263. + // This can happen if the extension specified a script to
  8264. + // be run in multiple rules, and the script has already run.
  8265. + // See crbug.com/631247.
  8266. + if (!should_inject_js && !should_inject_css) {
  8267. + return INJECTION_FINISHED;
  8268. + }
  8269. +
  8270. + if (should_inject_js)
  8271. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  8272. + &(scripts_run_info->num_js));
  8273. + if (should_inject_css)
  8274. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  8275. + &(scripts_run_info->num_css));
  8276. +
  8277. + complete_ = did_inject_js_ || !should_inject_js;
  8278. +
  8279. + if (complete_) {
  8280. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8281. + render_frame_);
  8282. + } else {
  8283. + ++scripts_run_info->num_blocking_js;
  8284. + }
  8285. +
  8286. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  8287. +}
  8288. +
  8289. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  8290. + size_t* num_injected_js_scripts) {
  8291. + DCHECK(!did_inject_js_);
  8292. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  8293. + run_location_, executing_scripts, num_injected_js_scripts);
  8294. + DCHECK(!sources.empty());
  8295. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  8296. + bool is_user_gesture = injector_->IsUserGesture();
  8297. +
  8298. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  8299. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  8300. +
  8301. + base::ElapsedTimer exec_timer;
  8302. +
  8303. + // For content scripts executing during page load, we run them asynchronously
  8304. + // in order to reduce UI jank experienced by the user. (We don't do this for
  8305. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  8306. + // run, so we run them as soon as we can.)
  8307. + // Note: We could potentially also run deferred and browser-driven scripts
  8308. + // asynchronously; however, these are rare enough that there probably isn't
  8309. + // UI jank. If this changes, we can update this.
  8310. + bool should_execute_asynchronously =
  8311. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  8312. + (run_location_ == UserScript::DOCUMENT_END ||
  8313. + run_location_ == UserScript::DOCUMENT_IDLE);
  8314. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  8315. + should_execute_asynchronously
  8316. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  8317. + : blink::WebLocalFrame::kSynchronous;
  8318. +
  8319. + render_frame_->GetWebFrame()->RequestExecuteScript(
  8320. + world_id, sources, is_user_gesture,
  8321. + execution_option, callback.release(),
  8322. + blink::BackForwardCacheAware::kPossiblyDisallow,
  8323. + blink::WebLocalFrame::PromiseBehavior::kDontWait);
  8324. +}
  8325. +
  8326. +void ScriptInjection::OnJsInjectionCompleted(
  8327. + const std::vector<v8::Local<v8::Value>>& results,
  8328. + absl::optional<base::TimeDelta> elapsed) {
  8329. + DCHECK(!did_inject_js_);
  8330. +
  8331. + bool expects_results = injector_->ExpectsResults();
  8332. + if (expects_results) {
  8333. + if (!results.empty() && !results[0].IsEmpty()) {
  8334. + // Right now, we only support returning single results (per frame).
  8335. + // It's safe to always use the main world context when converting
  8336. + // here. V8ValueConverterImpl shouldn't actually care about the
  8337. + // context scope, and it switches to v8::Object's creation context
  8338. + // when encountered.
  8339. + v8::Local<v8::Context> context =
  8340. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  8341. + execution_result_ =
  8342. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  8343. + }
  8344. + if (!execution_result_.get())
  8345. + execution_result_ = std::make_unique<base::Value>();
  8346. + }
  8347. + did_inject_js_ = true;
  8348. +
  8349. + // If |async_completion_callback_| is set, it means the script finished
  8350. + // asynchronously, and we should run it.
  8351. + if (!async_completion_callback_.is_null()) {
  8352. + complete_ = true;
  8353. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8354. + render_frame_);
  8355. + // Warning: this object can be destroyed after this line!
  8356. + std::move(async_completion_callback_).Run(this);
  8357. + }
  8358. +}
  8359. +
  8360. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  8361. + size_t* num_injected_stylesheets) {
  8362. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  8363. + run_location_, injected_stylesheets, num_injected_stylesheets);
  8364. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  8365. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  8366. + absl::optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  8367. + blink::WebCssOrigin blink_css_origin =
  8368. + css_origin && *css_origin == CSS_ORIGIN_USER
  8369. + ? blink::WebCssOrigin::kUser
  8370. + : blink::WebCssOrigin::kAuthor;
  8371. + blink::WebStyleSheetKey style_sheet_key;
  8372. + if (const absl::optional<std::string>& injection_key =
  8373. + injector_->GetInjectionKey())
  8374. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  8375. + for (const blink::WebString& css : css_sources)
  8376. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  8377. + blink_css_origin);
  8378. +}
  8379. +
  8380. +} // namespace extensions
  8381. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  8382. new file mode 100755
  8383. --- /dev/null
  8384. +++ b/components/user_scripts/renderer/script_injection.h
  8385. @@ -0,0 +1,154 @@
  8386. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8387. +// Use of this source code is governed by a BSD-style license that can be
  8388. +// found in the LICENSE file.
  8389. +
  8390. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8391. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8392. +
  8393. +#include <stdint.h>
  8394. +
  8395. +#include <memory>
  8396. +#include <vector>
  8397. +
  8398. +#include "base/callback.h"
  8399. +#include "base/memory/weak_ptr.h"
  8400. +#include "../common/user_script.h"
  8401. +#include "injection_host.h"
  8402. +#include "script_injector.h"
  8403. +
  8404. +struct HostID;
  8405. +
  8406. +namespace content {
  8407. +class RenderFrame;
  8408. +}
  8409. +
  8410. +namespace v8 {
  8411. +class Value;
  8412. +template <class T> class Local;
  8413. +}
  8414. +
  8415. +namespace user_scripts {
  8416. +struct ScriptsRunInfo;
  8417. +
  8418. +// A script wrapper which is aware of whether or not it is allowed to execute,
  8419. +// and contains the implementation to do so.
  8420. +class ScriptInjection {
  8421. + public:
  8422. + ScriptInjection(const ScriptInjection&) = delete;
  8423. + ScriptInjection& operator=(const ScriptInjection&) = delete;
  8424. + enum InjectionResult {
  8425. + INJECTION_FINISHED,
  8426. + INJECTION_BLOCKED,
  8427. + INJECTION_WAITING
  8428. + };
  8429. +
  8430. + using CompletionCallback = base::OnceCallback<void(ScriptInjection*)>;
  8431. +
  8432. + // Return the id of the injection host associated with the given world.
  8433. + static std::string GetHostIdForIsolatedWorld(int world_id);
  8434. +
  8435. + // Remove the isolated world associated with the given injection host.
  8436. + static void RemoveIsolatedWorld(const std::string& host_id);
  8437. +
  8438. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  8439. + content::RenderFrame* render_frame,
  8440. + std::unique_ptr<const InjectionHost> injection_host,
  8441. + UserScript::RunLocation run_location,
  8442. + bool log_activity);
  8443. + ~ScriptInjection();
  8444. +
  8445. + // Try to inject the script at the |current_location|. This returns
  8446. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  8447. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  8448. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  8449. + // for permission purposes or because |current_location| is not the designated
  8450. + // |run_location_|).
  8451. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  8452. + // called upon completion.
  8453. + InjectionResult TryToInject(
  8454. + UserScript::RunLocation current_location,
  8455. + ScriptsRunInfo* scripts_run_info,
  8456. + CompletionCallback async_completion_callback);
  8457. +
  8458. + // Called when permission for the given injection has been granted.
  8459. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  8460. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  8461. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  8462. +
  8463. + // Resets the pointer of the injection host when the host is gone.
  8464. + void OnHostRemoved();
  8465. +
  8466. + void invalidate_render_frame() { render_frame_ = nullptr; }
  8467. +
  8468. + // Accessors.
  8469. + content::RenderFrame* render_frame() const { return render_frame_; }
  8470. + const HostID& host_id() const { return injection_host_->id(); }
  8471. + int64_t request_id() const { return request_id_; }
  8472. +
  8473. + // Called when JS injection for the given frame has been completed or
  8474. + // cancelled.
  8475. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  8476. + absl::optional<base::TimeDelta> elapsed);
  8477. +
  8478. + private:
  8479. + class FrameWatcher;
  8480. +
  8481. + // Sends a message to the browser to request permission to inject.
  8482. + void RequestPermissionFromBrowser();
  8483. +
  8484. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  8485. + // otherwise INJECTION_BLOCKED.
  8486. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  8487. +
  8488. + // Inject any JS scripts into the frame for the injection.
  8489. + void InjectJs(std::set<std::string>* executing_scripts,
  8490. + size_t* num_injected_js_scripts);
  8491. +
  8492. + // Inject any CSS source into the frame for the injection.
  8493. + void InjectCss(std::set<std::string>* injected_stylesheets,
  8494. + size_t* num_injected_stylesheets);
  8495. +
  8496. + // Notify that we will not inject, and mark it as acknowledged.
  8497. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  8498. +
  8499. + // The injector for this injection.
  8500. + std::unique_ptr<ScriptInjector> injector_;
  8501. +
  8502. + // The RenderFrame into which this should inject the script.
  8503. + content::RenderFrame* render_frame_;
  8504. +
  8505. + // The associated injection host.
  8506. + std::unique_ptr<const InjectionHost> injection_host_;
  8507. +
  8508. + // The location in the document load at which we inject the script.
  8509. + UserScript::RunLocation run_location_;
  8510. +
  8511. + // This injection's request id. This will be -1 unless the injection is
  8512. + // currently waiting on permission.
  8513. + int64_t request_id_;
  8514. +
  8515. + // Whether or not the injection is complete, either via injecting the script
  8516. + // or because it will never complete.
  8517. + bool complete_;
  8518. +
  8519. + // Whether or not the injection successfully injected JS.
  8520. + bool did_inject_js_;
  8521. +
  8522. + // Whether or not we should log dom activity for this injection.
  8523. + bool log_activity_;
  8524. +
  8525. + // Results storage.
  8526. + std::unique_ptr<base::Value> execution_result_;
  8527. +
  8528. + // The callback to run upon completing asynchronously.
  8529. + CompletionCallback async_completion_callback_;
  8530. +
  8531. + // A helper class to hold the render frame and watch for its deletion.
  8532. + std::unique_ptr<FrameWatcher> frame_watcher_;
  8533. +
  8534. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  8535. +};
  8536. +
  8537. +} // namespace extensions
  8538. +
  8539. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8540. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  8541. new file mode 100755
  8542. --- /dev/null
  8543. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  8544. @@ -0,0 +1,25 @@
  8545. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8546. +// Use of this source code is governed by a BSD-style license that can be
  8547. +// found in the LICENSE file.
  8548. +
  8549. +#include "script_injection_callback.h"
  8550. +
  8551. +#include "third_party/blink/public/platform/web_vector.h"
  8552. +
  8553. +namespace user_scripts {
  8554. +
  8555. +ScriptInjectionCallback::ScriptInjectionCallback(
  8556. + CompleteCallback injection_completed_callback)
  8557. + : injection_completed_callback_(std::move(injection_completed_callback)) {}
  8558. +
  8559. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  8560. +}
  8561. +
  8562. +void ScriptInjectionCallback::Completed(
  8563. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  8564. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  8565. + std::move(injection_completed_callback_).Run(stl_result);
  8566. + delete this;
  8567. +}
  8568. +
  8569. +} // namespace extensions
  8570. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  8571. new file mode 100755
  8572. --- /dev/null
  8573. +++ b/components/user_scripts/renderer/script_injection_callback.h
  8574. @@ -0,0 +1,38 @@
  8575. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8576. +// Use of this source code is governed by a BSD-style license that can be
  8577. +// found in the LICENSE file.
  8578. +
  8579. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8580. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8581. +
  8582. +#include <vector>
  8583. +
  8584. +#include "base/callback.h"
  8585. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  8586. +#include "v8/include/v8.h"
  8587. +
  8588. +namespace user_scripts {
  8589. +
  8590. +// A wrapper around a callback to notify a script injection when injection
  8591. +// completes.
  8592. +// This class manages its own lifetime.
  8593. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  8594. + public:
  8595. + ScriptInjectionCallback(const ScriptInjectionCallback&) = delete;
  8596. + ScriptInjectionCallback& operator=(const ScriptInjectionCallback&) = delete;
  8597. + using CompleteCallback =
  8598. + base::OnceCallback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  8599. +
  8600. + explicit ScriptInjectionCallback(
  8601. + CompleteCallback injection_completed_callback);
  8602. + ~ScriptInjectionCallback() override;
  8603. +
  8604. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  8605. +
  8606. + private:
  8607. + CompleteCallback injection_completed_callback_;
  8608. +};
  8609. +
  8610. +} // namespace extensions
  8611. +
  8612. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8613. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  8614. new file mode 100755
  8615. --- /dev/null
  8616. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  8617. @@ -0,0 +1,417 @@
  8618. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8619. +// Use of this source code is governed by a BSD-style license that can be
  8620. +// found in the LICENSE file.
  8621. +
  8622. +#include "script_injection_manager.h"
  8623. +
  8624. +#include <memory>
  8625. +#include <utility>
  8626. +
  8627. +#include "base/auto_reset.h"
  8628. +#include "base/bind.h"
  8629. +#include "base/feature_list.h"
  8630. +#include "base/memory/weak_ptr.h"
  8631. +#include "base/threading/thread_task_runner_handle.h"
  8632. +#include "base/values.h"
  8633. +#include "base/logging.h"
  8634. +#include "content/public/renderer/render_frame.h"
  8635. +#include "content/public/renderer/render_frame_observer.h"
  8636. +#include "content/public/renderer/render_thread.h"
  8637. +#include "extension_frame_helper.h"
  8638. +#include "../common/host_id.h"
  8639. +#include "script_injection.h"
  8640. +#include "scripts_run_info.h"
  8641. +#include "web_ui_injection_host.h"
  8642. +#include "ipc/ipc_message_macros.h"
  8643. +#include "third_party/blink/public/platform/web_url_error.h"
  8644. +#include "third_party/blink/public/web/web_document.h"
  8645. +#include "third_party/blink/public/web/web_frame.h"
  8646. +#include "third_party/blink/public/web/web_local_frame.h"
  8647. +#include "third_party/blink/public/web/web_view.h"
  8648. +#include "url/gurl.h"
  8649. +#include "../common/user_scripts_features.h"
  8650. +
  8651. +namespace user_scripts {
  8652. +
  8653. +namespace {
  8654. +
  8655. +// The length of time to wait after the DOM is complete to try and run user
  8656. +// scripts.
  8657. +const int kScriptIdleTimeoutInMs = 200;
  8658. +
  8659. +// Returns the RunLocation that follows |run_location|.
  8660. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  8661. + switch (run_location) {
  8662. + case UserScript::DOCUMENT_START:
  8663. + return UserScript::DOCUMENT_END;
  8664. + case UserScript::DOCUMENT_END:
  8665. + return UserScript::DOCUMENT_IDLE;
  8666. + case UserScript::DOCUMENT_IDLE:
  8667. + return UserScript::RUN_LOCATION_LAST;
  8668. + case UserScript::UNDEFINED:
  8669. + case UserScript::RUN_DEFERRED:
  8670. + case UserScript::BROWSER_DRIVEN:
  8671. + case UserScript::RUN_LOCATION_LAST:
  8672. + break;
  8673. + }
  8674. + NOTREACHED();
  8675. + return UserScript::RUN_LOCATION_LAST;
  8676. +}
  8677. +
  8678. +} // namespace
  8679. +
  8680. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  8681. + public:
  8682. + RFOHelper(content::RenderFrame* render_frame,
  8683. + ScriptInjectionManager* manager);
  8684. + ~RFOHelper() override;
  8685. +
  8686. + // commit @9f2aac4
  8687. + void Initialize();
  8688. +
  8689. + private:
  8690. + // RenderFrameObserver implementation.
  8691. + void DidCreateNewDocument() override;
  8692. + void DidCreateDocumentElement() override;
  8693. + void DidFailProvisionalLoad() override;
  8694. + void DidDispatchDOMContentLoadedEvent() override;
  8695. + void WillDetach() override;
  8696. + void OnDestruct() override;
  8697. + void OnStop() override;
  8698. +
  8699. + // Tells the ScriptInjectionManager to run tasks associated with
  8700. + // document_idle.
  8701. + void RunIdle();
  8702. +
  8703. + void StartInjectScripts(UserScript::RunLocation run_location);
  8704. +
  8705. + // Indicate that the frame is no longer valid because it is starting
  8706. + // a new load or closing.
  8707. + void InvalidateAndResetFrame(bool force_reset);
  8708. +
  8709. + // The owning ScriptInjectionManager.
  8710. + ScriptInjectionManager* manager_;
  8711. +
  8712. + bool should_run_idle_ = true; // commit @9f2aac4
  8713. +
  8714. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  8715. +};
  8716. +
  8717. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  8718. + ScriptInjectionManager* manager)
  8719. + : content::RenderFrameObserver(render_frame),
  8720. + manager_(manager),
  8721. + should_run_idle_(true) {}
  8722. +
  8723. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  8724. +}
  8725. +
  8726. +
  8727. +void ScriptInjectionManager::RFOHelper::Initialize() {
  8728. + // Set up for the initial empty document, for which the Document created
  8729. + // events do not happen as it's already present.
  8730. + DidCreateNewDocument();
  8731. + // The initial empty document for a main frame may have scripts attached to it
  8732. + // but we do not want to invalidate the frame and lose them when the next
  8733. + // document loads. For example the IncognitoApiTest.IncognitoSplitMode test
  8734. + // does `chrome.tabs.create()` with a script to be run, which is added to the
  8735. + // frame before it navigates, so it needs to be preserved. However scripts in
  8736. + // child frames are expected to be run inside the initial empty document. For
  8737. + // example the ExecuteScriptApiTest.FrameWithHttp204 test creates a child
  8738. + // frame at about:blank and expects to run injected scripts inside it.
  8739. + // This is all quite inconsistent however tests both depend on us queuing and
  8740. + // not queueing the DOCUMENT_START events in the initial empty document.
  8741. + if (!render_frame()->IsMainFrame()) {
  8742. + DidCreateDocumentElement();
  8743. + }
  8744. +}
  8745. +
  8746. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  8747. + // A new document is going to be shown, so invalidate the old document state.
  8748. + // Don't force-reset the frame, because it is possible that a script injection
  8749. + // was scheduled before the page was loaded, e.g. by navigating to a
  8750. + // javascript: URL before the page has loaded.
  8751. + constexpr bool kForceReset = false;
  8752. + InvalidateAndResetFrame(kForceReset);
  8753. +}
  8754. +
  8755. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  8756. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8757. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  8758. +
  8759. + ExtensionFrameHelper::Get(render_frame())
  8760. + ->ScheduleAtDocumentStart(
  8761. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8762. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  8763. +}
  8764. +
  8765. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  8766. + auto it = manager_->frame_statuses_.find(render_frame());
  8767. + if (it != manager_->frame_statuses_.end() &&
  8768. + it->second == UserScript::DOCUMENT_START) {
  8769. + // Since the provisional load failed, the frame stays at its previous loaded
  8770. + // state and origin (or the parent's origin for new/about:blank frames).
  8771. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  8772. + // done loading, and avoid any deadlock in the system.
  8773. + //
  8774. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  8775. + // injections closely follow the DOMContentLoaded (and onload) events, which
  8776. + // are not triggered after a failed provisional load.
  8777. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  8778. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  8779. + constexpr bool kForceReset = true;
  8780. + InvalidateAndResetFrame(kForceReset);
  8781. + should_run_idle_ = false;
  8782. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  8783. + }
  8784. +}
  8785. +
  8786. +void ScriptInjectionManager::RFOHelper::DidDispatchDOMContentLoadedEvent() {
  8787. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8788. + LOG(INFO) << "UserScripts: DidDispatchDOMContentLoadedEvent -> DOCUMENT_END";
  8789. +
  8790. + DCHECK(content::RenderThread::Get());
  8791. + ExtensionFrameHelper::Get(render_frame())
  8792. + ->ScheduleAtDocumentEnd(
  8793. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8794. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8795. +
  8796. + // We try to run idle in two places: a delayed task here and in response to
  8797. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidDispatchDOMContentLoadedEvent()
  8798. + // corresponds to completing the document's load, whereas
  8799. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8800. + // subresources' load (but before the window.onload event). We don't want to
  8801. + // hold up script injection for a particularly slow subresource, so we set a
  8802. + // delayed task from here - but if we finish everything before that point
  8803. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8804. + // keep waiting.
  8805. + render_frame()
  8806. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8807. + ->PostDelayedTask(
  8808. + FROM_HERE,
  8809. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8810. + weak_factory_.GetWeakPtr()),
  8811. + base::Milliseconds(kScriptIdleTimeoutInMs));
  8812. +
  8813. + ExtensionFrameHelper::Get(render_frame())
  8814. + ->ScheduleAtDocumentIdle(
  8815. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8816. + weak_factory_.GetWeakPtr()));
  8817. +}
  8818. +
  8819. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8820. + // The frame is closing - invalidate.
  8821. + constexpr bool kForceReset = true;
  8822. + InvalidateAndResetFrame(kForceReset);
  8823. +}
  8824. +
  8825. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8826. + manager_->RemoveObserver(this);
  8827. +}
  8828. +
  8829. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8830. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8831. + // extension to avoid keeping the frame in a START state indefinitely which
  8832. + // leads to deadlocks.
  8833. + DidFailProvisionalLoad();
  8834. +}
  8835. +
  8836. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8837. + // Only notify the manager if the frame hasn't already had idle run since the
  8838. + // task to RunIdle() was posted.
  8839. + if (should_run_idle_) {
  8840. + should_run_idle_ = false;
  8841. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8842. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8843. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8844. + }
  8845. +}
  8846. +
  8847. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8848. + UserScript::RunLocation run_location) {
  8849. + manager_->StartInjectScripts(render_frame(), run_location);
  8850. +}
  8851. +
  8852. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8853. + bool force_reset) {
  8854. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8855. + weak_factory_.InvalidateWeakPtrs();
  8856. + // We reset to inject on idle, because the frame can be reused (in the case of
  8857. + // navigation).
  8858. + should_run_idle_ = true;
  8859. +
  8860. + // Reset the frame if either |force_reset| is true, or if the manager is
  8861. + // keeping track of the state of the frame (in which case we need to clean it
  8862. + // up).
  8863. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8864. + manager_->InvalidateForFrame(render_frame());
  8865. +}
  8866. +
  8867. +ScriptInjectionManager::ScriptInjectionManager(
  8868. + UserScriptSetManager* user_script_set_manager)
  8869. + : user_script_set_manager_(user_script_set_manager),
  8870. + user_script_set_manager_observation_(this) {
  8871. + user_script_set_manager_observation_.Observe(user_script_set_manager_);
  8872. +}
  8873. +
  8874. +ScriptInjectionManager::~ScriptInjectionManager() {
  8875. + for (const auto& injection : pending_injections_)
  8876. + injection->invalidate_render_frame();
  8877. + for (const auto& injection : running_injections_)
  8878. + injection->invalidate_render_frame();
  8879. +}
  8880. +
  8881. +void ScriptInjectionManager::OnRenderFrameCreated(
  8882. + content::RenderFrame* render_frame) {
  8883. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8884. + rfo_helpers_.back()->Initialize(); // commit @9f2aac4
  8885. +}
  8886. +
  8887. +void ScriptInjectionManager::OnInjectionFinished(
  8888. + ScriptInjection* injection) {
  8889. + auto iter =
  8890. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8891. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8892. + return injection == mode.get();
  8893. + });
  8894. + if (iter != running_injections_.end())
  8895. + running_injections_.erase(iter);
  8896. +}
  8897. +
  8898. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8899. + const std::set<HostID>& changed_hosts) {
  8900. + for (auto iter = pending_injections_.begin();
  8901. + iter != pending_injections_.end();) {
  8902. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8903. + iter = pending_injections_.erase(iter);
  8904. + else
  8905. + ++iter;
  8906. + }
  8907. +}
  8908. +
  8909. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8910. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8911. + if (iter->get() == helper) {
  8912. + rfo_helpers_.erase(iter);
  8913. + break;
  8914. + }
  8915. + }
  8916. +}
  8917. +
  8918. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8919. + // If the frame invalidated is the frame being injected into, we need to
  8920. + // note it.
  8921. + active_injection_frames_.erase(frame);
  8922. +
  8923. + for (auto iter = pending_injections_.begin();
  8924. + iter != pending_injections_.end();) {
  8925. + if ((*iter)->render_frame() == frame)
  8926. + iter = pending_injections_.erase(iter);
  8927. + else
  8928. + ++iter;
  8929. + }
  8930. +
  8931. + frame_statuses_.erase(frame);
  8932. +}
  8933. +
  8934. +void ScriptInjectionManager::StartInjectScripts(
  8935. + content::RenderFrame* frame,
  8936. + UserScript::RunLocation run_location) {
  8937. + auto iter = frame_statuses_.find(frame);
  8938. + // We also don't execute if we detect that the run location is somehow out of
  8939. + // order. This can happen if:
  8940. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8941. + // - The run location reported doesn't immediately follow the previous
  8942. + // reported run location.
  8943. + // We don't want to run because extensions may have requirements that scripts
  8944. + // running in an earlier run location have run by the time a later script
  8945. + // runs. Better to just not run.
  8946. + // Note that we check run_location > NextRunLocation() in the second clause
  8947. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8948. + // can happen multiple times, so we can receive earlier/equal run locations.
  8949. + if ((iter == frame_statuses_.end() &&
  8950. + run_location != UserScript::DOCUMENT_START) ||
  8951. + (iter != frame_statuses_.end() &&
  8952. + run_location > NextRunLocation(iter->second))) {
  8953. + // We also invalidate the frame, because the run order of pending injections
  8954. + // may also be bad.
  8955. + InvalidateForFrame(frame);
  8956. + return;
  8957. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8958. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8959. + // multiple times. Ignore the subsequent signals.
  8960. + return;
  8961. + }
  8962. +
  8963. + // Otherwise, all is right in the world, and we can get on with the
  8964. + // injections!
  8965. + frame_statuses_[frame] = run_location;
  8966. + InjectScripts(frame, run_location);
  8967. +}
  8968. +
  8969. +void ScriptInjectionManager::InjectScripts(
  8970. + content::RenderFrame* frame,
  8971. + UserScript::RunLocation run_location) {
  8972. + // Find any injections that want to run on the given frame.
  8973. + ScriptInjectionVector frame_injections;
  8974. + for (auto iter = pending_injections_.begin();
  8975. + iter != pending_injections_.end();) {
  8976. + if ((*iter)->render_frame() == frame) {
  8977. + frame_injections.push_back(std::move(*iter));
  8978. + iter = pending_injections_.erase(iter);
  8979. + } else {
  8980. + ++iter;
  8981. + }
  8982. + }
  8983. +
  8984. + // Add any injections for user scripts.
  8985. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  8986. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  8987. + run_location);
  8988. +
  8989. + // Note that we are running in |frame|.
  8990. + active_injection_frames_.insert(frame);
  8991. +
  8992. + ScriptsRunInfo scripts_run_info(frame, run_location);
  8993. +
  8994. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  8995. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  8996. + // (if a script removes its own frame, for example). If this happens, abort.
  8997. + if (!active_injection_frames_.count(frame))
  8998. + break;
  8999. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  9000. + iter = frame_injections.erase(iter);
  9001. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  9002. + }
  9003. +
  9004. + // We are done running in the frame.
  9005. + active_injection_frames_.erase(frame);
  9006. +
  9007. + scripts_run_info.LogRun(activity_logging_enabled_);
  9008. +}
  9009. +
  9010. +void ScriptInjectionManager::TryToInject(
  9011. + std::unique_ptr<ScriptInjection> injection,
  9012. + UserScript::RunLocation run_location,
  9013. + ScriptsRunInfo* scripts_run_info) {
  9014. + // Try to inject the script. If the injection is waiting (i.e., for
  9015. + // permission), add it to the list of pending injections. If the injection
  9016. + // has blocked, add it to the list of running injections.
  9017. + // The Unretained below is safe because this object owns all the
  9018. + // ScriptInjections, so is guaranteed to outlive them.
  9019. + switch (injection->TryToInject(
  9020. + run_location, scripts_run_info,
  9021. + base::BindOnce(&ScriptInjectionManager::OnInjectionFinished,
  9022. + base::Unretained(this)))) {
  9023. + case ScriptInjection::INJECTION_WAITING:
  9024. + pending_injections_.push_back(std::move(injection));
  9025. + break;
  9026. + case ScriptInjection::INJECTION_BLOCKED:
  9027. + running_injections_.push_back(std::move(injection));
  9028. + break;
  9029. + case ScriptInjection::INJECTION_FINISHED:
  9030. + break;
  9031. + }
  9032. +}
  9033. +
  9034. +} // namespace extensions
  9035. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  9036. new file mode 100755
  9037. --- /dev/null
  9038. +++ b/components/user_scripts/renderer/script_injection_manager.h
  9039. @@ -0,0 +1,101 @@
  9040. +#include <stdint.h>
  9041. +
  9042. +#include <map>
  9043. +#include <set>
  9044. +#include <string>
  9045. +#include <vector>
  9046. +
  9047. +#include "base/callback.h"
  9048. +#include "base/scoped_observation.h"
  9049. +#include "../common/user_script.h"
  9050. +#include "script_injection.h"
  9051. +#include "user_script_set_manager.h"
  9052. +
  9053. +namespace user_scripts {
  9054. +
  9055. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  9056. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  9057. +// maintaining any pending injections awaiting permission or the appropriate
  9058. +// load point, and injecting them when ready.
  9059. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  9060. + public:
  9061. + ScriptInjectionManager(const ScriptInjectionManager&) = delete;
  9062. + ScriptInjectionManager& operator=(const ScriptInjectionManager&) = delete;
  9063. + explicit ScriptInjectionManager(
  9064. + UserScriptSetManager* user_script_set_manager);
  9065. + virtual ~ScriptInjectionManager();
  9066. +
  9067. + // Notifies that a new render view has been created.
  9068. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  9069. +
  9070. + // Removes pending injections of the unloaded extension.
  9071. + //void OnExtensionUnloaded(const std::string& extension_id);
  9072. +
  9073. + void set_activity_logging_enabled(bool enabled) {
  9074. + activity_logging_enabled_ = enabled;
  9075. + }
  9076. +
  9077. + private:
  9078. + // A RenderFrameObserver implementation which watches the various render
  9079. + // frames in order to notify the ScriptInjectionManager of different
  9080. + // document load states and IPCs.
  9081. + class RFOHelper;
  9082. +
  9083. + using FrameStatusMap =
  9084. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  9085. +
  9086. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  9087. +
  9088. + // Notifies that an injection has been finished.
  9089. + void OnInjectionFinished(ScriptInjection* injection);
  9090. +
  9091. + // UserScriptSetManager::Observer implementation.
  9092. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  9093. +
  9094. + // Notifies that an RFOHelper should be removed.
  9095. + void RemoveObserver(RFOHelper* helper);
  9096. +
  9097. + // Invalidate any pending tasks associated with |frame|.
  9098. + void InvalidateForFrame(content::RenderFrame* frame);
  9099. +
  9100. + // Starts the process to inject appropriate scripts into |frame|.
  9101. + void StartInjectScripts(content::RenderFrame* frame,
  9102. + UserScript::RunLocation run_location);
  9103. +
  9104. + // Actually injects the scripts into |frame|.
  9105. + void InjectScripts(content::RenderFrame* frame,
  9106. + UserScript::RunLocation run_location);
  9107. +
  9108. + // Try to inject and store injection if it has not finished.
  9109. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  9110. + UserScript::RunLocation run_location,
  9111. + ScriptsRunInfo* scripts_run_info);
  9112. +
  9113. + // The map of active web frames to their corresponding statuses. The
  9114. + // RunLocation of the frame corresponds to the last location that has ran.
  9115. + FrameStatusMap frame_statuses_;
  9116. +
  9117. + // The frames currently being injected into, so long as that frame is valid.
  9118. + std::set<content::RenderFrame*> active_injection_frames_;
  9119. +
  9120. + // The collection of RFOHelpers.
  9121. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  9122. +
  9123. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  9124. + UserScriptSetManager* user_script_set_manager_;
  9125. +
  9126. + // Pending injections which are waiting for either the proper run location or
  9127. + // user consent.
  9128. + ScriptInjectionVector pending_injections_;
  9129. +
  9130. + // Running injections which are waiting for async callbacks from blink.
  9131. + ScriptInjectionVector running_injections_;
  9132. +
  9133. + // Whether or not dom activity should be logged for scripts injected.
  9134. + bool activity_logging_enabled_ = false;
  9135. +
  9136. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  9137. + user_script_set_manager_observation_{this};
  9138. +};
  9139. +
  9140. +}
  9141. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  9142. new file mode 100755
  9143. --- /dev/null
  9144. +++ b/components/user_scripts/renderer/script_injector.h
  9145. @@ -0,0 +1,96 @@
  9146. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9147. +// Use of this source code is governed by a BSD-style license that can be
  9148. +// found in the LICENSE file.
  9149. +
  9150. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9151. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9152. +
  9153. +#include <memory>
  9154. +#include <vector>
  9155. +
  9156. +#include "../common/constants.h"
  9157. +#include "../common/user_script.h"
  9158. +#include "third_party/blink/public/web/web_script_source.h"
  9159. +
  9160. +class InjectionHost;
  9161. +
  9162. +namespace blink {
  9163. +class WebLocalFrame;
  9164. +}
  9165. +
  9166. +namespace user_scripts {
  9167. +
  9168. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  9169. +// information about how to inject the script, including what code to inject and
  9170. +// when (run location), but without any injection logic.
  9171. +class ScriptInjector {
  9172. + public:
  9173. + // The possible reasons for not injecting the script.
  9174. + enum InjectFailureReason {
  9175. + EXTENSION_REMOVED, // The extension was removed before injection.
  9176. + NOT_ALLOWED, // The script is not allowed to inject.
  9177. + WONT_INJECT // The injection won't inject because the user rejected
  9178. + // (or just did not accept) the injection.
  9179. + };
  9180. +
  9181. + virtual ~ScriptInjector() {}
  9182. +
  9183. + // Returns the script type of this particular injection.
  9184. + virtual UserScript::InjectionType script_type() const = 0;
  9185. +
  9186. + // Returns true if the script is running inside a user gesture.
  9187. + virtual bool IsUserGesture() const = 0;
  9188. +
  9189. + // Returns the CSS origin of this injection.
  9190. + virtual absl::optional<CSSOrigin> GetCssOrigin() const = 0;
  9191. +
  9192. + // Returns the key for this injection, if it's a CSS injection.
  9193. + virtual const absl::optional<std::string> GetInjectionKey() const = 0;
  9194. +
  9195. + // Returns true if the script expects results.
  9196. + virtual bool ExpectsResults() const = 0;
  9197. +
  9198. + // Returns true if the script should inject JS source at the given
  9199. + // |run_location|.
  9200. + virtual bool ShouldInjectJs(
  9201. + UserScript::RunLocation run_location,
  9202. + const std::set<std::string>& executing_scripts) const = 0;
  9203. +
  9204. + // Returns true if the script should inject CSS at the given |run_location|.
  9205. + virtual bool ShouldInjectCss(
  9206. + UserScript::RunLocation run_location,
  9207. + const std::set<std::string>& injected_stylesheets) const = 0;
  9208. +
  9209. + // Returns the javascript sources to inject at the given |run_location|.
  9210. + // Only called if ShouldInjectJs() is true.
  9211. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  9212. + UserScript::RunLocation run_location,
  9213. + std::set<std::string>* executing_scripts,
  9214. + size_t* num_injected_js_scripts) const = 0;
  9215. +
  9216. + // Returns the css to inject at the given |run_location|.
  9217. + // Only called if ShouldInjectCss() is true.
  9218. + virtual std::vector<blink::WebString> GetCssSources(
  9219. + UserScript::RunLocation run_location,
  9220. + std::set<std::string>* injected_stylesheets,
  9221. + size_t* num_injected_stylesheets) const = 0;
  9222. +
  9223. + // Notifies the script that injection has completed, with a possibly-populated
  9224. + // list of results (depending on whether or not ExpectsResults() was true).
  9225. + // |render_frame| contains the render frame, or null if the frame was
  9226. + // invalidated.
  9227. + virtual void OnInjectionComplete(
  9228. + std::unique_ptr<base::Value> execution_result,
  9229. + UserScript::RunLocation run_location,
  9230. + content::RenderFrame* render_frame) = 0;
  9231. +
  9232. + // Notifies the script that injection will never occur.
  9233. + // |render_frame| contains the render frame, or null if the frame was
  9234. + // invalidated.
  9235. + virtual void OnWillNotInject(InjectFailureReason reason,
  9236. + content::RenderFrame* render_frame) = 0;
  9237. +};
  9238. +
  9239. +} // namespace extensions
  9240. +
  9241. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9242. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  9243. new file mode 100755
  9244. --- /dev/null
  9245. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  9246. @@ -0,0 +1,31 @@
  9247. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9248. +// Use of this source code is governed by a BSD-style license that can be
  9249. +// found in the LICENSE file.
  9250. +
  9251. +#include "scripts_run_info.h"
  9252. +
  9253. +#include "base/metrics/histogram_macros.h"
  9254. +#include "content/public/renderer/render_frame.h"
  9255. +#include "content/public/renderer/render_thread.h"
  9256. +#include "script_context.h"
  9257. +#include "third_party/blink/public/web/web_local_frame.h"
  9258. +
  9259. +namespace user_scripts {
  9260. +
  9261. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  9262. + UserScript::RunLocation location)
  9263. + : num_css(0u),
  9264. + num_js(0u),
  9265. + num_blocking_js(0u),
  9266. + routing_id_(render_frame->GetRoutingID()),
  9267. + run_location_(location),
  9268. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  9269. + render_frame->GetWebFrame())) {}
  9270. +
  9271. +ScriptsRunInfo::~ScriptsRunInfo() {
  9272. +}
  9273. +
  9274. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  9275. +}
  9276. +
  9277. +} // namespace extensions
  9278. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  9279. new file mode 100755
  9280. --- /dev/null
  9281. +++ b/components/user_scripts/renderer/scripts_run_info.h
  9282. @@ -0,0 +1,69 @@
  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. +#ifndef USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9288. +#define USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9289. +
  9290. +#include <stddef.h>
  9291. +
  9292. +#include <map>
  9293. +#include <set>
  9294. +#include <string>
  9295. +
  9296. +#include "base/timer/elapsed_timer.h"
  9297. +#include "../common/user_script.h"
  9298. +
  9299. +namespace content {
  9300. +class RenderFrame;
  9301. +}
  9302. +
  9303. +namespace user_scripts {
  9304. +
  9305. +// A struct containing information about a script run.
  9306. +struct ScriptsRunInfo {
  9307. + ScriptsRunInfo(const ScriptsRunInfo&) = delete;
  9308. + ScriptsRunInfo& operator=(const ScriptsRunInfo&) = delete;
  9309. + // Map of extensions IDs to the executing script paths.
  9310. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  9311. +
  9312. + ScriptsRunInfo(content::RenderFrame* render_frame,
  9313. + UserScript::RunLocation location);
  9314. + ~ScriptsRunInfo();
  9315. +
  9316. + // The number of CSS scripts injected.
  9317. + size_t num_css;
  9318. + // The number of JS scripts injected.
  9319. + size_t num_js;
  9320. + // The number of blocked JS scripts injected.
  9321. + size_t num_blocking_js;
  9322. + // A map of extension ids to executing script paths.
  9323. + ExecutingScriptsMap executing_scripts;
  9324. + // A map of extension ids to injected stylesheet paths.
  9325. + ExecutingScriptsMap injected_stylesheets;
  9326. + // The elapsed time since the ScriptsRunInfo was constructed.
  9327. + base::ElapsedTimer timer;
  9328. +
  9329. + // Log information about a given script run. If |send_script_activity| is
  9330. + // true, this also informs the browser of the script run.
  9331. + void LogRun(bool send_script_activity);
  9332. +
  9333. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  9334. + const base::TimeDelta& elapsed);
  9335. +
  9336. + private:
  9337. + // The routinig id to use to notify the browser of any injections. Since the
  9338. + // frame may be deleted in injection, we don't hold on to a reference to it
  9339. + // directly.
  9340. + int routing_id_;
  9341. +
  9342. + // The run location at which injection is happening.
  9343. + UserScript::RunLocation run_location_;
  9344. +
  9345. + // The url of the frame, preserved for the same reason as the routing id.
  9346. + GURL frame_url_;
  9347. +};
  9348. +
  9349. +} // namespace extensions
  9350. +
  9351. +#endif // USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9352. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  9353. new file mode 100755
  9354. --- /dev/null
  9355. +++ b/components/user_scripts/renderer/user_script_injector.cc
  9356. @@ -0,0 +1,228 @@
  9357. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9358. +// Use of this source code is governed by a BSD-style license that can be
  9359. +// found in the LICENSE file.
  9360. +
  9361. +#include "user_script_injector.h"
  9362. +
  9363. +#include <tuple>
  9364. +#include <vector>
  9365. +
  9366. +#include "base/logging.h"
  9367. +#include "base/lazy_instance.h"
  9368. +#include "content/public/common/url_constants.h"
  9369. +#include "content/public/renderer/render_frame.h"
  9370. +#include "content/public/renderer/render_thread.h"
  9371. +#include "content/public/renderer/render_view.h"
  9372. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  9373. +#include "injection_host.h"
  9374. +#include "script_context.h"
  9375. +#include "scripts_run_info.h"
  9376. +#include "third_party/blink/public/web/web_document.h"
  9377. +#include "third_party/blink/public/web/web_local_frame.h"
  9378. +#include "third_party/blink/public/web/web_script_source.h"
  9379. +#include "ui/base/resource/resource_bundle.h"
  9380. +#include "url/gurl.h"
  9381. +
  9382. +namespace user_scripts {
  9383. +
  9384. +namespace {
  9385. +
  9386. +struct RoutingInfoKey {
  9387. + int routing_id;
  9388. + int script_id;
  9389. +
  9390. + RoutingInfoKey(int routing_id, int script_id)
  9391. + : routing_id(routing_id), script_id(script_id) {}
  9392. +
  9393. + bool operator<(const RoutingInfoKey& other) const {
  9394. + return std::tie(routing_id, script_id) <
  9395. + std::tie(other.routing_id, other.script_id);
  9396. + }
  9397. +};
  9398. +
  9399. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  9400. +
  9401. +// A map records whether a given |script_id| from a webview-added user script
  9402. +// is allowed to inject on the render of given |routing_id|.
  9403. +// Once a script is added, the decision of whether or not allowed to inject
  9404. +// won't be changed.
  9405. +// After removed by the webview, the user scipt will also be removed
  9406. +// from the render. Therefore, there won't be any query from the same
  9407. +// |script_id| and |routing_id| pair.
  9408. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  9409. +// LAZY_INSTANCE_INITIALIZER;
  9410. +
  9411. +// Greasemonkey API source that is injected with the scripts.
  9412. +struct GreasemonkeyApiJsString {
  9413. + GreasemonkeyApiJsString();
  9414. + blink::WebScriptSource GetSource() const;
  9415. +
  9416. + private:
  9417. + blink::WebString source_;
  9418. +};
  9419. +
  9420. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  9421. +// the GreasemonkeyApiJs resource.
  9422. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  9423. + std::string greasemonky_api_js(
  9424. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  9425. + IDR_GREASEMONKEY_API_JS));
  9426. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  9427. +}
  9428. +
  9429. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  9430. + return blink::WebScriptSource(source_);
  9431. +}
  9432. +
  9433. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  9434. + LAZY_INSTANCE_INITIALIZER;
  9435. +
  9436. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  9437. + const std::set<std::string>& injected_files) {
  9438. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  9439. + // Check if the script is already injected.
  9440. + if (injected_files.count(file->url().path()) == 0) {
  9441. + return true;
  9442. + }
  9443. + }
  9444. + return false;
  9445. +}
  9446. +
  9447. +} // namespace
  9448. +
  9449. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  9450. + UserScriptSet* script_list)
  9451. + : script_(script),
  9452. + user_script_set_(script_list),
  9453. + script_id_(script_->id()),
  9454. + user_script_set_observer_(this) {
  9455. + user_script_set_observer_.Observe(script_list);
  9456. +}
  9457. +
  9458. +UserScriptInjector::~UserScriptInjector() {
  9459. +}
  9460. +
  9461. +void UserScriptInjector::OnUserScriptsUpdated(
  9462. + const std::set<HostID>& changed_hosts,
  9463. + const UserScriptList& scripts) {
  9464. + // When user scripts are updated, all the old script pointers are invalidated.
  9465. + script_ = nullptr;
  9466. + // If the host causing this injection changed, then this injection
  9467. + // will be removed, and there's no guarantee the backing script still exists.
  9468. + // if (changed_hosts.count(host_id_) > 0)
  9469. + // return;
  9470. +
  9471. + for (const std::unique_ptr<UserScript>& script : scripts) {
  9472. + if (script->id() == script_id_) {
  9473. + script_ = script.get();
  9474. + break;
  9475. + }
  9476. + }
  9477. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  9478. + // should be guaranteed to exist.
  9479. + DCHECK(script_);
  9480. +}
  9481. +
  9482. +UserScript::InjectionType UserScriptInjector::script_type() const {
  9483. + return UserScript::CONTENT_SCRIPT;
  9484. +}
  9485. +
  9486. +bool UserScriptInjector::IsUserGesture() const {
  9487. + return false;
  9488. +}
  9489. +
  9490. +bool UserScriptInjector::ExpectsResults() const {
  9491. + return false;
  9492. +}
  9493. +
  9494. +absl::optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  9495. + return absl::nullopt;
  9496. +}
  9497. +
  9498. +const absl::optional<std::string> UserScriptInjector::GetInjectionKey() const {
  9499. + return absl::nullopt;
  9500. +}
  9501. +
  9502. +bool UserScriptInjector::ShouldInjectJs(
  9503. + UserScript::RunLocation run_location,
  9504. + const std::set<std::string>& executing_scripts) const {
  9505. + return script_ && script_->run_location() == run_location &&
  9506. + !script_->js_scripts().empty() &&
  9507. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  9508. +}
  9509. +
  9510. +bool UserScriptInjector::ShouldInjectCss(
  9511. + UserScript::RunLocation run_location,
  9512. + const std::set<std::string>& injected_stylesheets) const {
  9513. + return script_ && run_location == UserScript::DOCUMENT_START &&
  9514. + !script_->css_scripts().empty() &&
  9515. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  9516. +}
  9517. +
  9518. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  9519. + UserScript::RunLocation run_location,
  9520. + std::set<std::string>* executing_scripts,
  9521. + size_t* num_injected_js_scripts) const {
  9522. + DCHECK(script_);
  9523. + std::vector<blink::WebScriptSource> sources;
  9524. +
  9525. + DCHECK_EQ(script_->run_location(), run_location);
  9526. +
  9527. + const UserScript::FileList& js_scripts = script_->js_scripts();
  9528. + sources.reserve(js_scripts.size() +
  9529. + (script_->emulate_greasemonkey() ? 1 : 0));
  9530. + // Emulate Greasemonkey API for scripts that were converted to extension
  9531. + // user scripts.
  9532. + if (script_->emulate_greasemonkey())
  9533. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  9534. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  9535. + const GURL& script_url = file->url();
  9536. + // Check if the script is already injected.
  9537. + if (executing_scripts->count(script_url.path()) != 0)
  9538. + continue;
  9539. +
  9540. + sources.push_back(blink::WebScriptSource(
  9541. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  9542. + script_url));
  9543. +
  9544. + (*num_injected_js_scripts) += 1;
  9545. + executing_scripts->insert(script_url.path());
  9546. + }
  9547. +
  9548. + return sources;
  9549. +}
  9550. +
  9551. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  9552. + UserScript::RunLocation run_location,
  9553. + std::set<std::string>* injected_stylesheets,
  9554. + size_t* num_injected_stylesheets) const {
  9555. + DCHECK(script_);
  9556. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  9557. +
  9558. + std::vector<blink::WebString> sources;
  9559. +
  9560. + const UserScript::FileList& css_scripts = script_->css_scripts();
  9561. + sources.reserve(css_scripts.size());
  9562. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  9563. + const std::string& stylesheet_path = file->url().path();
  9564. + // Check if the stylesheet is already injected.
  9565. + if (injected_stylesheets->count(stylesheet_path) != 0)
  9566. + continue;
  9567. +
  9568. + sources.push_back(user_script_set_->GetCssSource(*file));
  9569. + (*num_injected_stylesheets) += 1;
  9570. + injected_stylesheets->insert(stylesheet_path);
  9571. + }
  9572. + return sources;
  9573. +}
  9574. +
  9575. +void UserScriptInjector::OnInjectionComplete(
  9576. + std::unique_ptr<base::Value> execution_result,
  9577. + UserScript::RunLocation run_location,
  9578. + content::RenderFrame* render_frame) {}
  9579. +
  9580. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  9581. + content::RenderFrame* render_frame) {
  9582. +}
  9583. +
  9584. +} // namespace extensions
  9585. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  9586. new file mode 100755
  9587. --- /dev/null
  9588. +++ b/components/user_scripts/renderer/user_script_injector.h
  9589. @@ -0,0 +1,86 @@
  9590. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9591. +// Use of this source code is governed by a BSD-style license that can be
  9592. +// found in the LICENSE file.
  9593. +
  9594. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9595. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9596. +
  9597. +#include <memory>
  9598. +#include <string>
  9599. +
  9600. +#include "base/values.h"
  9601. +#include "base/scoped_observation.h"
  9602. +#include "../common/user_script.h"
  9603. +#include "script_injection.h"
  9604. +#include "user_script_set.h"
  9605. +
  9606. +class InjectionHost;
  9607. +
  9608. +namespace blink {
  9609. +class WebLocalFrame;
  9610. +}
  9611. +
  9612. +namespace user_scripts {
  9613. +
  9614. +// A ScriptInjector for UserScripts.
  9615. +class UserScriptInjector : public ScriptInjector,
  9616. + public UserScriptSet::Observer {
  9617. + public:
  9618. + UserScriptInjector(const UserScriptInjector&) = delete;
  9619. + UserScriptInjector& operator=(const UserScriptInjector&) = delete;
  9620. + UserScriptInjector(const UserScript* user_script,
  9621. + UserScriptSet* user_script_set);
  9622. + ~UserScriptInjector() override;
  9623. +
  9624. + private:
  9625. + // UserScriptSet::Observer implementation.
  9626. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9627. + const UserScriptList& scripts) override;
  9628. +
  9629. + // ScriptInjector implementation.
  9630. + UserScript::InjectionType script_type() const override;
  9631. + bool IsUserGesture() const override;
  9632. + absl::optional<CSSOrigin> GetCssOrigin() const override;
  9633. + const absl::optional<std::string> GetInjectionKey() const override;
  9634. + bool ExpectsResults() const override;
  9635. + bool ShouldInjectJs(
  9636. + UserScript::RunLocation run_location,
  9637. + const std::set<std::string>& executing_scripts) const override;
  9638. + bool ShouldInjectCss(
  9639. + UserScript::RunLocation run_location,
  9640. + const std::set<std::string>& injected_stylesheets) const override;
  9641. + std::vector<blink::WebScriptSource> GetJsSources(
  9642. + UserScript::RunLocation run_location,
  9643. + std::set<std::string>* executing_scripts,
  9644. + size_t* num_injected_js_scripts) const override;
  9645. + std::vector<blink::WebString> GetCssSources(
  9646. + UserScript::RunLocation run_location,
  9647. + std::set<std::string>* injected_stylesheets,
  9648. + size_t* num_injected_stylesheets) const override;
  9649. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  9650. + UserScript::RunLocation run_location,
  9651. + content::RenderFrame* render_frame) override;
  9652. + void OnWillNotInject(InjectFailureReason reason,
  9653. + content::RenderFrame* render_frame) override;
  9654. +
  9655. + // The associated user script. Owned by the UserScriptInjector that created
  9656. + // this object.
  9657. + const UserScript* script_;
  9658. +
  9659. + // The UserScriptSet that eventually owns the UserScript this
  9660. + // UserScriptInjector points to.
  9661. + // Outlives |this|.
  9662. + UserScriptSet* const user_script_set_;
  9663. +
  9664. + // The id of the associated user script. We cache this because when we update
  9665. + // the |script_| associated with this injection, the old referance may be
  9666. + // deleted.
  9667. + int script_id_;
  9668. +
  9669. + base::ScopedObservation<UserScriptSet, UserScriptSet::Observer>
  9670. + user_script_set_observer_{this};
  9671. +};
  9672. +
  9673. +} // namespace extensions
  9674. +
  9675. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9676. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  9677. new file mode 100755
  9678. --- /dev/null
  9679. +++ b/components/user_scripts/renderer/user_script_set.cc
  9680. @@ -0,0 +1,262 @@
  9681. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9682. +// Use of this source code is governed by a BSD-style license that can be
  9683. +// found in the LICENSE file.
  9684. +
  9685. +#include "user_script_set.h"
  9686. +
  9687. +#include <stddef.h>
  9688. +
  9689. +#include <utility>
  9690. +
  9691. +#include "base/logging.h"
  9692. +#include "base/debug/alias.h"
  9693. +#include "base/memory/ref_counted.h"
  9694. +#include "base/strings/strcat.h"
  9695. +#include "content/public/common/url_constants.h"
  9696. +#include "content/public/renderer/render_frame.h"
  9697. +#include "content/public/renderer/render_thread.h"
  9698. +#include "injection_host.h"
  9699. +#include "script_context.h"
  9700. +#include "script_injection.h"
  9701. +#include "user_script_injector.h"
  9702. +#include "web_ui_injection_host.h"
  9703. +#include "third_party/blink/public/web/web_document.h"
  9704. +#include "third_party/blink/public/web/web_local_frame.h"
  9705. +#include "url/gurl.h"
  9706. +#include "../common/user_scripts_features.h"
  9707. +
  9708. +namespace user_scripts {
  9709. +
  9710. +namespace {
  9711. +
  9712. +// These two strings are injected before and after the Greasemonkey API and
  9713. +// user script to wrap it in an anonymous scope.
  9714. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  9715. +const char kUserScriptTail[] = "\n})(window);";
  9716. +// Maximum number of total content scripts we allow (across all extensions).
  9717. +// The limit exists to diagnose https://crbug.com/723381. The number is
  9718. +// arbitrarily chosen.
  9719. +// TODO(lazyboy): Remove when the bug is fixed.
  9720. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  9721. +
  9722. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  9723. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  9724. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  9725. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  9726. + data_source_url.spec());
  9727. + }
  9728. +
  9729. + return data_source_url;
  9730. +}
  9731. +
  9732. +} // namespace
  9733. +
  9734. +UserScriptSet::UserScriptSet() {}
  9735. +
  9736. +UserScriptSet::~UserScriptSet() {
  9737. +}
  9738. +
  9739. +void UserScriptSet::AddObserver(Observer* observer) {
  9740. + observers_.AddObserver(observer);
  9741. +}
  9742. +
  9743. +void UserScriptSet::RemoveObserver(Observer* observer) {
  9744. + observers_.RemoveObserver(observer);
  9745. +}
  9746. +
  9747. +void UserScriptSet::GetInjections(
  9748. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9749. + content::RenderFrame* render_frame,
  9750. + int tab_id,
  9751. + UserScript::RunLocation run_location,
  9752. + bool log_activity) {
  9753. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  9754. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  9755. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  9756. + script.get(), render_frame, tab_id, run_location, document_url,
  9757. + /* is_declarative, */ log_activity);
  9758. + if (injection.get())
  9759. + injections->push_back(std::move(injection));
  9760. + }
  9761. +}
  9762. +
  9763. +bool UserScriptSet::UpdateUserScripts(
  9764. + base::ReadOnlySharedMemoryRegion shared_memory,
  9765. + const std::set<HostID>& changed_hosts,
  9766. + bool whitelisted_only) {
  9767. + bool only_inject_incognito = false;
  9768. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  9769. +
  9770. + // Create the shared memory mapping.
  9771. + shared_memory_mapping_ = shared_memory.Map();
  9772. + if (!shared_memory.IsValid())
  9773. + return false;
  9774. +
  9775. + // First get the size of the memory block.
  9776. + const base::Pickle::Header* pickle_header =
  9777. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  9778. + if (!pickle_header)
  9779. + return false;
  9780. +
  9781. + // Now read in the rest of the block.
  9782. + size_t pickle_size =
  9783. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  9784. +
  9785. + // Unpickle scripts.
  9786. + uint32_t num_scripts = 0;
  9787. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9788. + if (!memory.size())
  9789. + return false;
  9790. +
  9791. + base::Pickle pickle(memory.data(), pickle_size);
  9792. + base::PickleIterator iter(pickle);
  9793. + base::debug::Alias(&pickle_size);
  9794. + CHECK(iter.ReadUInt32(&num_scripts));
  9795. +
  9796. + // Sometimes the shared memory contents seem to be corrupted
  9797. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9798. + // scripts so that we don't add OOM noise to crash reports.
  9799. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9800. +
  9801. + scripts_.clear();
  9802. + script_sources_.clear();
  9803. + scripts_.reserve(num_scripts);
  9804. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9805. + std::unique_ptr<UserScript> script(new UserScript());
  9806. + script->Unpickle(pickle, &iter);
  9807. +
  9808. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9809. + // cleared up when the last renderer or browser process drops their
  9810. + // reference to the shared memory.
  9811. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9812. + const char* body = NULL;
  9813. + int body_length = 0;
  9814. + CHECK(iter.ReadData(&body, &body_length));
  9815. + script->js_scripts()[j]->set_external_content(
  9816. + base::StringPiece(body, body_length));
  9817. + }
  9818. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9819. + const char* body = NULL;
  9820. + int body_length = 0;
  9821. + CHECK(iter.ReadData(&body, &body_length));
  9822. + script->css_scripts()[j]->set_external_content(
  9823. + base::StringPiece(body, body_length));
  9824. + }
  9825. +
  9826. + if (only_inject_incognito && !script->is_incognito_enabled())
  9827. + continue; // This script shouldn't run in an incognito tab.
  9828. +
  9829. + scripts_.push_back(std::move(script));
  9830. + }
  9831. +
  9832. + for (auto& observer : observers_)
  9833. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9834. + return true;
  9835. +}
  9836. +
  9837. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9838. + scripts_.push_back(std::move(script));
  9839. +}
  9840. +
  9841. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9842. + const UserScript* script,
  9843. + content::RenderFrame* render_frame,
  9844. + int tab_id,
  9845. + UserScript::RunLocation run_location,
  9846. + const GURL& document_url,
  9847. + //bool is_declarative,
  9848. + bool log_activity) {
  9849. + std::unique_ptr<ScriptInjection> injection;
  9850. + std::unique_ptr<const InjectionHost> injection_host;
  9851. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9852. +
  9853. + const HostID& host_id = script->host_id();
  9854. + injection_host.reset(new WebUIInjectionHost(host_id));
  9855. +
  9856. + GURL effective_document_url =
  9857. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9858. + web_frame, document_url, script->match_origin_as_fallback());
  9859. +
  9860. + bool is_subframe = web_frame->Parent();
  9861. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9862. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9863. + LOG(INFO) << "UserScripts: No Match name=" << script->name() <<
  9864. + " id=" << script->host_id().id() <<
  9865. + " url=" << effective_document_url.spec();
  9866. + return injection;
  9867. + }
  9868. +
  9869. + std::unique_ptr<ScriptInjector> injector(
  9870. + new UserScriptInjector(script, this));
  9871. +
  9872. + bool inject_css = !script->css_scripts().empty() &&
  9873. + run_location == UserScript::DOCUMENT_START;
  9874. + bool inject_js =
  9875. + !script->js_scripts().empty() && script->run_location() == run_location;
  9876. + if (inject_css || inject_js) {
  9877. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9878. + std::move(injection_host), run_location,
  9879. + log_activity));
  9880. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9881. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9882. + "url=" << effective_document_url.spec();
  9883. + } else {
  9884. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9885. + if (script->run_location() != run_location)
  9886. + LOG(INFO) << "UserScripts: run location for name=" << script->name() <<
  9887. + " id=" << script->host_id().id() <<
  9888. + " current " << run_location <<
  9889. + " need " << script->run_location();
  9890. + else
  9891. + LOG(INFO) << "UserScripts: Match but no run name=" << script->name() <<
  9892. + " id=" << script->host_id().id() <<
  9893. + " url=" << effective_document_url.spec();
  9894. + }
  9895. + }
  9896. + return injection;
  9897. +}
  9898. +
  9899. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9900. + bool emulate_greasemonkey) {
  9901. + const GURL& url = file.url();
  9902. + auto iter = script_sources_.find(url);
  9903. + if (iter != script_sources_.end()) {
  9904. + return iter->second;
  9905. + }
  9906. +
  9907. + base::StringPiece script_content = file.GetContent();
  9908. + blink::WebString source;
  9909. + if (emulate_greasemonkey) {
  9910. + // We add this dumb function wrapper for user scripts to emulate what
  9911. + // Greasemonkey does. |script_content| becomes:
  9912. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9913. + std::string content =
  9914. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9915. + source = blink::WebString::FromUTF8(content);
  9916. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9917. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9918. + } else {
  9919. + source = blink::WebString::FromUTF8(script_content.data(),
  9920. + script_content.length());
  9921. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9922. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9923. + }
  9924. + script_sources_[url] = source;
  9925. + return source;
  9926. +}
  9927. +
  9928. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9929. + const GURL& url = file.url();
  9930. + auto iter = script_sources_.find(url);
  9931. + if (iter != script_sources_.end())
  9932. + return iter->second;
  9933. +
  9934. + base::StringPiece script_content = file.GetContent();
  9935. + return script_sources_
  9936. + .insert(std::make_pair(
  9937. + url, blink::WebString::FromUTF8(script_content.data(),
  9938. + script_content.length())))
  9939. + .first->second;
  9940. +}
  9941. +
  9942. +} // namespace extensions
  9943. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9944. new file mode 100755
  9945. --- /dev/null
  9946. +++ b/components/user_scripts/renderer/user_script_set.h
  9947. @@ -0,0 +1,101 @@
  9948. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9949. +// Use of this source code is governed by a BSD-style license that can be
  9950. +// found in the LICENSE file.
  9951. +
  9952. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9953. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9954. +
  9955. +#include <map>
  9956. +#include <memory>
  9957. +#include <set>
  9958. +#include <string>
  9959. +#include <vector>
  9960. +
  9961. +#include "base/memory/read_only_shared_memory_region.h"
  9962. +#include "base/observer_list.h"
  9963. +#include "../common/user_script.h"
  9964. +#include "third_party/blink/public/platform/web_string.h"
  9965. +
  9966. +class GURL;
  9967. +
  9968. +namespace content {
  9969. +class RenderFrame;
  9970. +}
  9971. +
  9972. +namespace user_scripts {
  9973. +class ScriptInjection;
  9974. +
  9975. +// The UserScriptSet is a collection of UserScripts which knows how to update
  9976. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  9977. +// inject on a page.
  9978. +class UserScriptSet {
  9979. + public:
  9980. + UserScriptSet(const UserScriptSet&) = delete;
  9981. + UserScriptSet& operator=(const UserScriptSet&) = delete;
  9982. + class Observer {
  9983. + public:
  9984. + // Called when the set of user scripts is updated. |changed_hosts| contains
  9985. + // the hosts whose scripts have been altered. Note that *all* script objects
  9986. + // are invalidated, even if they aren't in |changed_hosts|.
  9987. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9988. + const UserScriptList& scripts) = 0;
  9989. + };
  9990. +
  9991. + UserScriptSet();
  9992. + ~UserScriptSet();
  9993. +
  9994. + // Adds or removes observers.
  9995. + void AddObserver(Observer* observer);
  9996. + void RemoveObserver(Observer* observer);
  9997. + void AddScript(std::unique_ptr<UserScript> script);
  9998. +
  9999. + // Append any ScriptInjections that should run on the given |render_frame| and
  10000. + // |tab_id|, at the given |run_location|, to |injections|.
  10001. + // |extensions| is passed in to verify the corresponding extension is still
  10002. + // valid.
  10003. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10004. + content::RenderFrame* render_frame,
  10005. + int tab_id,
  10006. + UserScript::RunLocation run_location,
  10007. + bool log_activity);
  10008. +
  10009. + // Updates scripts given the shared memory region containing user scripts.
  10010. + // Returns true if the scripts were successfully updated.
  10011. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  10012. + const std::set<HostID>& changed_hosts,
  10013. + bool whitelisted_only);
  10014. +
  10015. + // Returns the contents of a script file.
  10016. + // Note that copying is cheap as this uses WebString.
  10017. + blink::WebString GetJsSource(const UserScript::File& file,
  10018. + bool emulate_greasemonkey);
  10019. + blink::WebString GetCssSource(const UserScript::File& file);
  10020. +
  10021. + private:
  10022. + // Returns a new ScriptInjection for the given |script| to execute in the
  10023. + // |render_frame|, or NULL if the script should not execute.
  10024. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  10025. + const UserScript* script,
  10026. + content::RenderFrame* render_frame,
  10027. + int tab_id,
  10028. + UserScript::RunLocation run_location,
  10029. + const GURL& document_url,
  10030. + //bool is_declarative,
  10031. + bool log_activity);
  10032. +
  10033. + // Shared memory mapping containing raw script data.
  10034. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  10035. +
  10036. + // The UserScripts this injector manages.
  10037. + UserScriptList scripts_;
  10038. +
  10039. + // Map of user script file url -> source.
  10040. + std::map<GURL, blink::WebString> script_sources_;
  10041. +
  10042. + // The associated observers.
  10043. + base::ObserverList<Observer>::Unchecked observers_;
  10044. +};
  10045. +
  10046. +} // namespace extensions
  10047. +
  10048. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  10049. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  10050. new file mode 100755
  10051. --- /dev/null
  10052. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  10053. @@ -0,0 +1,77 @@
  10054. +#include "user_script_set_manager.h"
  10055. +
  10056. +#include "base/logging.h"
  10057. +#include "content/public/renderer/render_thread.h"
  10058. +#include "../common/host_id.h"
  10059. +#include "../common/extension_messages.h"
  10060. +#include "../common/user_scripts_features.h"
  10061. +#include "user_script_set.h"
  10062. +
  10063. +namespace user_scripts {
  10064. +
  10065. +UserScriptSetManager::UserScriptSetManager() {
  10066. + content::RenderThread::Get()->AddObserver(this);
  10067. +}
  10068. +
  10069. +UserScriptSetManager::~UserScriptSetManager() {
  10070. +}
  10071. +
  10072. +void UserScriptSetManager::AddObserver(Observer* observer) {
  10073. + observers_.AddObserver(observer);
  10074. +}
  10075. +
  10076. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  10077. + observers_.RemoveObserver(observer);
  10078. +}
  10079. +
  10080. +bool UserScriptSetManager::OnControlMessageReceived(
  10081. + const IPC::Message& message) {
  10082. + bool handled = true;
  10083. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  10084. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  10085. + IPC_MESSAGE_UNHANDLED(handled = false)
  10086. + IPC_END_MESSAGE_MAP()
  10087. + return handled;
  10088. +}
  10089. +
  10090. +void UserScriptSetManager::GetAllInjections(
  10091. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10092. + content::RenderFrame* render_frame,
  10093. + int tab_id,
  10094. + UserScript::RunLocation run_location) {
  10095. +
  10096. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10097. + LOG(INFO) << "UserScripts: GetAllInjections";
  10098. +
  10099. + // static_scripts_ is UserScriptSet
  10100. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  10101. + activity_logging_enabled_);
  10102. +}
  10103. +
  10104. +void UserScriptSetManager::OnUpdateUserScripts(
  10105. + base::ReadOnlySharedMemoryRegion shared_memory) {
  10106. + if (!shared_memory.IsValid()) {
  10107. + NOTREACHED() << "Bad scripts handle";
  10108. + return;
  10109. + }
  10110. +
  10111. + UserScriptSet* scripts = NULL;
  10112. + scripts = &static_scripts_;
  10113. +
  10114. + DCHECK(scripts);
  10115. +
  10116. + // If no hosts are included in the set, that indicates that all
  10117. + // hosts were updated. Add them all to the set so that observers and
  10118. + // individual UserScriptSets don't need to know this detail.
  10119. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  10120. + std::set<HostID> all_hosts;
  10121. + const std::set<HostID>* effective_hosts = &all_hosts;
  10122. +
  10123. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  10124. + false /*whitelisted_only*/)) {
  10125. + for (auto& observer : observers_)
  10126. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  10127. + }
  10128. +}
  10129. +
  10130. +}
  10131. \ No newline at end of file
  10132. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  10133. new file mode 100755
  10134. --- /dev/null
  10135. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  10136. @@ -0,0 +1,61 @@
  10137. +#ifndef USERSCRIPTS_RENDER_SET_MANAGER_H_
  10138. +#define USERSCRIPTS_RENDER_SET_MANAGER_H_
  10139. +
  10140. +#include <map>
  10141. +#include <set>
  10142. +#include <string>
  10143. +#include <vector>
  10144. +
  10145. +#include "base/memory/read_only_shared_memory_region.h"
  10146. +#include "base/observer_list.h"
  10147. +#include "content/public/renderer/render_thread_observer.h"
  10148. +#include "../common/host_id.h"
  10149. +#include "user_script_set.h"
  10150. +#include "script_injection.h"
  10151. +
  10152. +namespace user_scripts {
  10153. +
  10154. +class UserScriptSetManager : public content::RenderThreadObserver {
  10155. + public:
  10156. + class Observer {
  10157. + public:
  10158. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  10159. + };
  10160. +
  10161. + UserScriptSetManager();
  10162. +
  10163. + ~UserScriptSetManager() override;
  10164. +
  10165. + void AddObserver(Observer* observer);
  10166. + void RemoveObserver(Observer* observer);
  10167. +
  10168. + // Append all injections from |static_scripts| and each of
  10169. + // |programmatic_scripts_| to |injections|.
  10170. + void GetAllInjections(
  10171. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10172. + content::RenderFrame* render_frame,
  10173. + int tab_id,
  10174. + UserScript::RunLocation run_location);
  10175. +
  10176. +private:
  10177. + // content::RenderThreadObserver implementation.
  10178. + bool OnControlMessageReceived(const IPC::Message& message) override;
  10179. +
  10180. + base::ObserverList<Observer>::Unchecked observers_;
  10181. +
  10182. + // Handle the UpdateUserScripts extension message.
  10183. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  10184. + //, const HostID& host_id,
  10185. + //const std::set<HostID>& changed_hosts,
  10186. + //bool whitelisted_only);
  10187. +
  10188. + // Scripts statically defined in extension manifests.
  10189. + UserScriptSet static_scripts_;
  10190. +
  10191. + // Whether or not dom activity should be logged for scripts injected.
  10192. + bool activity_logging_enabled_ = false;
  10193. +};
  10194. +
  10195. +}
  10196. +
  10197. +#endif
  10198. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10199. new file mode 100755
  10200. --- /dev/null
  10201. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10202. @@ -0,0 +1,36 @@
  10203. +#include "user_scripts_dispatcher.h"
  10204. +
  10205. +#include <stddef.h>
  10206. +
  10207. +#include <algorithm>
  10208. +#include <memory>
  10209. +#include <utility>
  10210. +
  10211. +#include "content/public/renderer/render_thread.h"
  10212. +#include "extension_frame_helper.h"
  10213. +
  10214. +namespace user_scripts {
  10215. +
  10216. +// ex ChromeExtensionsDispatcherDelegate
  10217. +UserScriptsDispatcher::UserScriptsDispatcher()
  10218. + : user_script_set_manager_observer_(this) {
  10219. + user_script_set_manager_.reset(new UserScriptSetManager());
  10220. + script_injection_manager_.reset(
  10221. + new ScriptInjectionManager(user_script_set_manager_.get()));
  10222. + user_script_set_manager_observer_.Observe(user_script_set_manager_.get());
  10223. +}
  10224. +
  10225. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  10226. +}
  10227. +
  10228. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  10229. +}
  10230. +
  10231. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  10232. +}
  10233. +
  10234. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  10235. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  10236. +}
  10237. +
  10238. +}
  10239. \ No newline at end of file
  10240. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10241. new file mode 100755
  10242. --- /dev/null
  10243. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10244. @@ -0,0 +1,49 @@
  10245. +#ifndef USERSCRIPTS_RENDER_DISPATCHER_H_
  10246. +#define USERSCRIPTS_RENDER_DISPATCHER_H_
  10247. +
  10248. +#include "user_script_set_manager.h"
  10249. +#include "script_injection_manager.h"
  10250. +
  10251. +#include <stdint.h>
  10252. +
  10253. +#include <map>
  10254. +#include <memory>
  10255. +#include <set>
  10256. +#include <string>
  10257. +#include <utility>
  10258. +#include <vector>
  10259. +
  10260. +#include "base/scoped_observation.h"
  10261. +#include "content/public/renderer/render_thread_observer.h"
  10262. +#include "content/public/renderer/render_thread.h"
  10263. +#include "../common/host_id.h"
  10264. +#include "user_script_set_manager.h"
  10265. +#include "script_injection.h"
  10266. +
  10267. +namespace user_scripts {
  10268. +
  10269. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  10270. + public UserScriptSetManager::Observer {
  10271. +
  10272. + public:
  10273. + UserScriptsDispatcher(const UserScriptsDispatcher&) = delete;
  10274. + UserScriptsDispatcher& operator=(const UserScriptsDispatcher&) = delete;
  10275. + explicit UserScriptsDispatcher();
  10276. + ~UserScriptsDispatcher() override;
  10277. +
  10278. + void OnRenderThreadStarted(content::RenderThread* thread);
  10279. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  10280. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  10281. +
  10282. + private:
  10283. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  10284. +
  10285. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  10286. +
  10287. + base::ScopedObservation<UserScriptSetManager, UserScriptSetManager::Observer>
  10288. + user_script_set_manager_observer_{this};
  10289. +};
  10290. +
  10291. +}
  10292. +
  10293. +#endif
  10294. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10295. new file mode 100755
  10296. --- /dev/null
  10297. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10298. @@ -0,0 +1,105 @@
  10299. +#include "user_scripts_renderer_client.h"
  10300. +
  10301. +#include <memory>
  10302. +#include <utility>
  10303. +
  10304. +#include "base/logging.h"
  10305. +#include "base/lazy_instance.h"
  10306. +#include "content/public/renderer/render_frame.h"
  10307. +#include "content/public/renderer/render_thread.h"
  10308. +#include "content/public/renderer/render_frame_visitor.h"
  10309. +#include "chrome/renderer/chrome_render_thread_observer.h"
  10310. +
  10311. +#include "../common/user_scripts_features.h"
  10312. +#include "user_scripts_dispatcher.h"
  10313. +#include "extension_frame_helper.h"
  10314. +
  10315. +namespace user_scripts {
  10316. +
  10317. +// was ChromeExtensionsRendererClient
  10318. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  10319. +
  10320. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  10321. +
  10322. +// static
  10323. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  10324. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  10325. + LAZY_INSTANCE_INITIALIZER;
  10326. + return client.Pointer();
  10327. +}
  10328. +
  10329. +void UserScriptsRendererClient::RenderThreadStarted() {
  10330. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10331. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  10332. +
  10333. + content::RenderThread* thread = content::RenderThread::Get();
  10334. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  10335. +
  10336. + dispatcher_->OnRenderThreadStarted(thread);
  10337. + thread->AddObserver(dispatcher_.get());
  10338. +}
  10339. +
  10340. +void UserScriptsRendererClient::ConfigurationUpdated() {
  10341. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10342. + LOG(INFO) << "UserScripts: Configuration Updated";
  10343. +
  10344. + struct WatchFrame : public content::RenderFrameVisitor {
  10345. + bool Visit(content::RenderFrame* frame) override {
  10346. + if (frame)
  10347. + UserScriptsRendererClient::GetInstance()->RenderFrameCreated(frame, NULL);
  10348. + return true; // Continue visiting.
  10349. + }
  10350. + };
  10351. + WatchFrame visitor = {};
  10352. + content::RenderFrame::ForEach(&visitor);
  10353. +}
  10354. +
  10355. +void UserScriptsRendererClient::RenderFrameCreated(
  10356. + content::RenderFrame* render_frame,
  10357. + service_manager::BinderRegistry* registry) {
  10358. +
  10359. + auto params = ChromeRenderThreadObserver::GetDynamicParams();
  10360. + enabled_ = params.allow_userscript;
  10361. + if (!enabled_) return;
  10362. +
  10363. + if (loaded_ == false) {
  10364. + loaded_ = true;
  10365. + new user_scripts::ExtensionFrameHelper(render_frame);
  10366. + dispatcher_->OnRenderFrameCreated(render_frame);
  10367. + }
  10368. +}
  10369. +
  10370. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  10371. + if (!enabled_ || !loaded_) return;
  10372. +
  10373. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10374. + if (!frame_helper)
  10375. + return; // The frame is invisible to user scripts.
  10376. +
  10377. + frame_helper->RunScriptsAtDocumentStart();
  10378. + // |frame_helper| and |render_frame| might be dead by now.
  10379. +}
  10380. +
  10381. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  10382. + if (!enabled_ || !loaded_) return;
  10383. +
  10384. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10385. + if (!frame_helper)
  10386. + return; // The frame is invisible to user scripts.
  10387. +
  10388. + frame_helper->RunScriptsAtDocumentEnd();
  10389. + // |frame_helper| and |render_frame| might be dead by now.
  10390. +}
  10391. +
  10392. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  10393. + if (!enabled_ || !loaded_) return;
  10394. +
  10395. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10396. + if (!frame_helper)
  10397. + return; // The frame is invisible to user scripts.
  10398. +
  10399. + frame_helper->RunScriptsAtDocumentIdle();
  10400. + // |frame_helper| and |render_frame| might be dead by now.
  10401. +}
  10402. +
  10403. +}
  10404. \ No newline at end of file
  10405. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10406. new file mode 100755
  10407. --- /dev/null
  10408. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10409. @@ -0,0 +1,37 @@
  10410. +#ifndef USERSCRIPTS_RENDER_CLIENT_H_
  10411. +#define USERSCRIPTS_RENDER_CLIENT_H_
  10412. +
  10413. +#include <memory>
  10414. +#include <string>
  10415. +
  10416. +#include "user_scripts_dispatcher.h"
  10417. +#include "services/service_manager/public/cpp/binder_registry.h"
  10418. +
  10419. +namespace user_scripts {
  10420. +
  10421. +class UserScriptsRendererClient {
  10422. + public:
  10423. + UserScriptsRendererClient(const UserScriptsRendererClient&) = delete;
  10424. + UserScriptsRendererClient& operator=(const UserScriptsRendererClient&) = delete;
  10425. + UserScriptsRendererClient();
  10426. + ~UserScriptsRendererClient();
  10427. +
  10428. + static UserScriptsRendererClient* GetInstance();
  10429. +
  10430. + void RenderThreadStarted();
  10431. + void ConfigurationUpdated();
  10432. + void RenderFrameCreated(content::RenderFrame* render_frame,
  10433. + service_manager::BinderRegistry* registry);
  10434. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  10435. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  10436. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  10437. +
  10438. + private:
  10439. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  10440. + bool enabled_ = false;
  10441. + bool loaded_ = false;
  10442. +};
  10443. +
  10444. +}
  10445. +
  10446. +#endif
  10447. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  10448. new file mode 100755
  10449. --- /dev/null
  10450. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  10451. @@ -0,0 +1,40 @@
  10452. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10453. +// Use of this source code is governed by a BSD-style license that can be
  10454. +// found in the LICENSE file.
  10455. +
  10456. +#include "web_ui_injection_host.h"
  10457. +#include "base/no_destructor.h"
  10458. +
  10459. +namespace {
  10460. +
  10461. +// The default secure CSP to be used in order to prevent remote scripts.
  10462. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  10463. +
  10464. +}
  10465. +
  10466. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  10467. + : InjectionHost(host_id),
  10468. + url_(host_id.id()) {
  10469. +}
  10470. +
  10471. +WebUIInjectionHost::~WebUIInjectionHost() {
  10472. +}
  10473. +
  10474. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  10475. + // Use the main world CSP.
  10476. + // return nullptr;
  10477. +
  10478. + // The isolated world will use its own CSP which blocks remotely hosted
  10479. + // code.
  10480. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  10481. + kDefaultSecureCSP);
  10482. + return default_isolated_world_csp.get();
  10483. +}
  10484. +
  10485. +const GURL& WebUIInjectionHost::url() const {
  10486. + return url_;
  10487. +}
  10488. +
  10489. +const std::string& WebUIInjectionHost::name() const {
  10490. + return id().id();
  10491. +}
  10492. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  10493. new file mode 100755
  10494. --- /dev/null
  10495. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  10496. @@ -0,0 +1,27 @@
  10497. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10498. +// Use of this source code is governed by a BSD-style license that can be
  10499. +// found in the LICENSE file.
  10500. +
  10501. +#ifndef USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10502. +#define USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10503. +
  10504. +#include "injection_host.h"
  10505. +
  10506. +class WebUIInjectionHost : public InjectionHost {
  10507. + public:
  10508. + WebUIInjectionHost(const WebUIInjectionHost&) = delete;
  10509. + WebUIInjectionHost& operator=(const WebUIInjectionHost&) = delete;
  10510. + WebUIInjectionHost(const HostID& host_id);
  10511. + ~WebUIInjectionHost() override;
  10512. +
  10513. + private:
  10514. + // InjectionHost:
  10515. + const std::string* GetContentSecurityPolicy() const override;
  10516. + const GURL& url() const override;
  10517. + const std::string& name() const override;
  10518. +
  10519. + private:
  10520. + GURL url_;
  10521. +};
  10522. +
  10523. +#endif // USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10524. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  10525. new file mode 100755
  10526. --- /dev/null
  10527. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  10528. @@ -0,0 +1,57 @@
  10529. +<?xml version="1.0" encoding="utf-8"?>
  10530. +<grit-part>
  10531. +
  10532. + <!-- Preferences -->
  10533. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  10534. + desc="."
  10535. + formatter_data="android_java">
  10536. + User Scripts
  10537. + </message>
  10538. +
  10539. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  10540. + Activate User Scripts
  10541. + </message>
  10542. +
  10543. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10544. + ON
  10545. + </message>
  10546. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10547. + OFF
  10548. + </message>
  10549. +
  10550. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10551. + Add script
  10552. + </message>
  10553. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  10554. + Experimental support for Greasemonkey-style user scripts.
  10555. + </message>
  10556. +
  10557. + <message name="IDS_SCRIPTS_ITEM_VERSION" desc="." formatter_data="android_java">
  10558. + Version:
  10559. + </message>
  10560. + <message name="IDS_SCRIPTS_ITEM_FILENAME" desc="." formatter_data="android_java">
  10561. + File:
  10562. + </message>
  10563. + <message name="IDS_SCRIPTS_ITEM_URL" desc="." formatter_data="android_java">
  10564. + Url:
  10565. + </message>
  10566. +
  10567. + <message name="IDS_SCRIPTS_VIEW_SOURCE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10568. + View source
  10569. + </message>
  10570. +
  10571. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10572. + Do you want to install this user script from following location?
  10573. +
  10574. +<ph name="FILE">%s</ph>
  10575. +
  10576. +NOTE: only install user scripts that you have verified are secure, user scripts can steal your credentials and data.
  10577. + </message>
  10578. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10579. + Yes
  10580. + </message>
  10581. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10582. + No
  10583. + </message>
  10584. +
  10585. +</grit-part>
  10586. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  10587. --- a/tools/gritsettings/resource_ids.spec
  10588. +++ b/tools/gritsettings/resource_ids.spec
  10589. @@ -649,6 +649,12 @@
  10590. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  10591. "includes": [3720]
  10592. },
  10593. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  10594. + "includes": [6000],
  10595. + },
  10596. + "components/user_scripts/browser/resources/browser_resources.grd": {
  10597. + "includes": [6020],
  10598. + },
  10599. # END components/ section.
  10600. # START ios/ section.
  10601. --
  10602. 2.25.1